зеркало из https://github.com/microsoft/Power-Fx.git
Connectors: fix default value logic and export functions to yml (#1913)
This commit is contained in:
Родитель
c2f9bbdad5
Коммит
7874752d05
|
@ -355,14 +355,12 @@ Output/
|
|||
# Tool folder
|
||||
tool/
|
||||
|
||||
# Report folder
|
||||
report/
|
||||
|
||||
# ApiCompat suppression files
|
||||
suppress.*.xml
|
||||
|
||||
# Connector analysis reports
|
||||
/report/Analysis.txt
|
||||
/report/Report.json
|
||||
/report/Report_*.json
|
||||
|
||||
# global.json
|
||||
/src/global.json
|
||||
/global.json
|
||||
|
|
|
@ -827,6 +827,11 @@ namespace Microsoft.PowerFx.Connectors
|
|||
// Only used by ConnectorTexlFunction
|
||||
private DType[] GetParamTypes()
|
||||
{
|
||||
if (RequiredParameters == null)
|
||||
{
|
||||
return Array.Empty<DType>();
|
||||
}
|
||||
|
||||
IEnumerable<DType> parameterTypes = RequiredParameters.Select(parameter => parameter.FormulaType._type);
|
||||
if (OptionalParameters.Any())
|
||||
{
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
}
|
||||
else if (param.Schema.Default != null)
|
||||
{
|
||||
if (OpenApiExtensions.TryGetOpenApiValue(param.Schema.Default, out FormulaValue defaultValue))
|
||||
if (OpenApiExtensions.TryGetOpenApiValue(param.Schema.Default, null, out FormulaValue defaultValue))
|
||||
{
|
||||
bodyParts.Add(param.Name, (param.Schema, defaultValue));
|
||||
}
|
||||
|
@ -239,9 +239,19 @@ namespace Microsoft.PowerFx.Connectors
|
|||
lst.Remove(field1);
|
||||
lst.Add(field2);
|
||||
}
|
||||
else if (field1.Value is BlankValue)
|
||||
{
|
||||
lst.Remove(field1);
|
||||
lst.Add(field2);
|
||||
}
|
||||
else if (field2.Value is BlankValue)
|
||||
{
|
||||
lst.Remove(field2);
|
||||
lst.Add(field1);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Cannot merge {field1.Name} of type {field1.Value.GetType().Name} with {field2.Name} of type {field2.Value.GetType().Name}");
|
||||
throw new ArgumentException($"Cannot merge '{field1.Name}' of type {field1.Value.GetType().Name} with '{field2.Name}' of type {field2.Value.GetType().Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,47 +123,104 @@ namespace Microsoft.PowerFx.Connectors
|
|||
}
|
||||
|
||||
public static bool TryGetDefaultValue(this OpenApiSchema schema, FormulaType formulaType, out FormulaValue defaultValue)
|
||||
{
|
||||
IOpenApiAny openApiDefaultValue = schema.Default;
|
||||
|
||||
if (openApiDefaultValue == null)
|
||||
{
|
||||
if (formulaType is RecordType rt && schema.Properties != null)
|
||||
{
|
||||
List<NamedValue> values = new List<NamedValue>();
|
||||
|
||||
foreach (NamedFormulaType nft in rt.GetFieldTypes())
|
||||
{
|
||||
string columnName = nft.Name.Value;
|
||||
|
||||
if (schema.Properties.ContainsKey(columnName))
|
||||
{
|
||||
if (schema.Properties[columnName].TryGetDefaultValue(nft.Type, out FormulaValue innerDefaultValue))
|
||||
{
|
||||
values.Add(new NamedValue(columnName, innerDefaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (values.Any())
|
||||
{
|
||||
defaultValue = new InMemoryRecordValue(IRContext.NotInSource(rt), values);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
defaultValue = null;
|
||||
return false;
|
||||
{
|
||||
if (schema.Type == "array" && formulaType is TableType tableType && schema.Items != null)
|
||||
{
|
||||
RecordType recordType = tableType.ToRecord();
|
||||
bool b = schema.Items.TryGetDefaultValue(recordType, out FormulaValue itemDefaultValue);
|
||||
|
||||
if (!b || itemDefaultValue is BlankValue)
|
||||
{
|
||||
defaultValue = FormulaValue.NewTable(recordType);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (itemDefaultValue is RecordValue itemDefaultRecordValue)
|
||||
{
|
||||
defaultValue = FormulaValue.NewTable(recordType, itemDefaultRecordValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
defaultValue = FormulaValue.NewTable(recordType, FormulaValue.NewRecordFromFields(new NamedValue[] { new NamedValue(TableValue.ValueName, itemDefaultValue) }));
|
||||
return true;
|
||||
}
|
||||
|
||||
return TryGetOpenApiValue(openApiDefaultValue, out defaultValue);
|
||||
if (schema.Type == "object" || schema.Default == null)
|
||||
{
|
||||
if (formulaType is RecordType recordType2 && schema.Properties != null)
|
||||
{
|
||||
List<NamedValue> values = new List<NamedValue>();
|
||||
|
||||
foreach (NamedFormulaType namedFormulaType in recordType2.GetFieldTypes())
|
||||
{
|
||||
string columnName = namedFormulaType.Name.Value;
|
||||
|
||||
if (schema.Properties.ContainsKey(columnName))
|
||||
{
|
||||
if (schema.Properties[columnName].TryGetDefaultValue(namedFormulaType.Type, out FormulaValue innerDefaultValue))
|
||||
{
|
||||
values.Add(new NamedValue(columnName, innerDefaultValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add(new NamedValue(columnName, FormulaValue.NewBlank(namedFormulaType.Type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultValue = values.Any(v => v.Value is not BlankValue) ? FormulaValue.NewRecordFromFields(values) : FormulaValue.NewBlank(recordType2);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (schema.Default == null)
|
||||
{
|
||||
defaultValue = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return TryGetOpenApiValue(schema.Default, formulaType, out defaultValue);
|
||||
}
|
||||
|
||||
internal static bool TryGetOpenApiValue(IOpenApiAny openApiAny, out FormulaValue formulaValue)
|
||||
internal static bool TryGetOpenApiValue(IOpenApiAny openApiAny, FormulaType formulaType, out FormulaValue formulaValue)
|
||||
{
|
||||
if (openApiAny is OpenApiString str)
|
||||
{
|
||||
formulaValue = FormulaValue.New(str.Value);
|
||||
{
|
||||
formulaValue = null;
|
||||
|
||||
if (formulaType != null && formulaType is not StringType && formulaType is not RecordType)
|
||||
{
|
||||
if (formulaType is BooleanType && bool.TryParse(str.Value, out bool b))
|
||||
{
|
||||
formulaValue = FormulaValue.New(b);
|
||||
}
|
||||
else if (formulaType is DecimalType && decimal.TryParse(str.Value, out decimal d))
|
||||
{
|
||||
formulaValue = FormulaValue.New(d);
|
||||
}
|
||||
else if (formulaType is DateTimeType)
|
||||
{
|
||||
if (DateTime.TryParse(str.Value, out DateTime dt))
|
||||
{
|
||||
formulaValue = FormulaValue.New(dt);
|
||||
}
|
||||
|
||||
throw new PowerFxConnectorException($"Unsupported DateTime format: {str.Value}");
|
||||
}
|
||||
else if (formulaType is NumberType && double.TryParse(str.Value, out double dbl))
|
||||
{
|
||||
formulaValue = FormulaValue.New(dbl);
|
||||
}
|
||||
else if (formulaType is OptionSetValueType osvt && osvt.TryGetValue(new DName(str.Value), out OptionSetValue osv))
|
||||
{
|
||||
formulaValue = osv;
|
||||
}
|
||||
}
|
||||
|
||||
if (formulaValue == null)
|
||||
{
|
||||
formulaValue = FormulaValue.New(str.Value);
|
||||
}
|
||||
}
|
||||
else if (openApiAny is OpenApiInteger intVal)
|
||||
{
|
||||
|
@ -210,7 +267,17 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
foreach (IOpenApiAny element in arr)
|
||||
{
|
||||
bool ba = TryGetOpenApiValue(element, out FormulaValue fv);
|
||||
FormulaType newType = null;
|
||||
|
||||
if (formulaType != null)
|
||||
{
|
||||
if (formulaType is TableType tableType)
|
||||
{
|
||||
newType = tableType.ToRecord();
|
||||
}
|
||||
}
|
||||
|
||||
bool ba = TryGetOpenApiValue(element, newType, out FormulaValue fv);
|
||||
if (!ba)
|
||||
{
|
||||
formulaValue = null;
|
||||
|
@ -232,7 +299,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
foreach (KeyValuePair<string, IOpenApiAny> kvp in o)
|
||||
{
|
||||
if (TryGetOpenApiValue(kvp.Value, out FormulaValue fv))
|
||||
if (TryGetOpenApiValue(kvp.Value, null, out FormulaValue fv))
|
||||
{
|
||||
dvParams[kvp.Key] = fv;
|
||||
}
|
||||
|
@ -390,7 +457,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
return new ConnectorType(schema, openApiParameter, FormulaType.UntypedObject);
|
||||
}
|
||||
|
||||
chain.Push(innerA);
|
||||
chain.Push(innerA);
|
||||
ConnectorType arrayType = new OpenApiParameter() { Name = "Array", Required = true, Schema = schema.Items, Extensions = schema.Items.Extensions }.ToConnectorType(chain, level + 1);
|
||||
|
||||
chain.Pop();
|
||||
|
@ -536,13 +603,13 @@ namespace Microsoft.PowerFx.Connectors
|
|||
}
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
// No return type. Void() method.
|
||||
{
|
||||
// No return type. Void() method.
|
||||
return (new ConnectorType(), null);
|
||||
}
|
||||
|
||||
if (response.Content.Count == 0)
|
||||
{
|
||||
{
|
||||
OpenApiSchema schema = new OpenApiSchema() { Type = "string", Format = "binary" };
|
||||
ConnectorType connectorType = new OpenApiParameter() { Name = "response", Required = true, Schema = schema, Extensions = response.Extensions }.ToConnectorType();
|
||||
return (connectorType, null);
|
||||
|
@ -727,7 +794,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
foreach (KeyValuePair<string, IOpenApiAny> prm in opPrms)
|
||||
{
|
||||
if (!OpenApiExtensions.TryGetOpenApiValue(prm.Value, out FormulaValue fv))
|
||||
if (!OpenApiExtensions.TryGetOpenApiValue(prm.Value, null, out FormulaValue fv))
|
||||
{
|
||||
throw new NotImplementedException($"Unsupported param with OpenApi type {prm.Value.GetType().FullName}, key = {prm.Key}");
|
||||
}
|
||||
|
|
|
@ -383,6 +383,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
isSupported = false;
|
||||
notSupportedReason = $"OpenApiParameter is null";
|
||||
logger?.LogWarning($"OperationId {op.OperationId} has a null OpenApiParameter");
|
||||
return;
|
||||
}
|
||||
|
||||
if (param.Deprecated)
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
public string Title => Schema.Title;
|
||||
|
||||
public FormulaType FormulaType => UseHiddenTypes ? ConnectorType.HiddenRecordType : ConnectorType.FormulaType;
|
||||
|
||||
|
||||
internal RecordType HiddenRecordType => ConnectorType.HiddenRecordType;
|
||||
|
||||
public string Summary => ConnectorExtensions.Summary;
|
||||
|
@ -36,8 +36,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
Schema = openApiParameter.Schema;
|
||||
UseHiddenTypes = useHiddenTypes;
|
||||
ConnectorType = openApiParameter.ToConnectorType();
|
||||
DefaultValue = openApiParameter.Schema.TryGetDefaultValue(FormulaType, out FormulaValue defaultValue) ? defaultValue : null;
|
||||
|
||||
DefaultValue = openApiParameter.Schema.TryGetDefaultValue(FormulaType, out FormulaValue defaultValue) && defaultValue is not BlankValue ? defaultValue : null;
|
||||
ConnectorExtensions = new ConnectorExtensions(openApiParameter, bodyExtensions);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
if (IsEnum)
|
||||
{
|
||||
EnumValues = schema.Enum.Select(oaa => OpenApiExtensions.TryGetOpenApiValue(oaa, out FormulaValue fv) ? fv : throw new NotSupportedException($"Invalid conversion for type {oaa.GetType().Name} in enum")).ToArray();
|
||||
EnumValues = schema.Enum.Select(oaa => OpenApiExtensions.TryGetOpenApiValue(oaa, null, out FormulaValue fv) ? fv : throw new NotSupportedException($"Invalid conversion for type {oaa.GetType().Name} in enum")).ToArray();
|
||||
EnumDisplayNames = schema.Extensions != null && schema.Extensions.TryGetValue(XMsEnumDisplayName, out IOpenApiExtension enumNames) && enumNames is OpenApiArray oaa
|
||||
? oaa.Cast<OpenApiString>().Select(oas => oas.Value).ToArray()
|
||||
: Array.Empty<string>();
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.PowerFx.Tests;
|
||||
using Microsoft.VisualStudio.TestPlatform.Utilities;
|
||||
using Microsoft.PowerFx.Types;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Microsoft.PowerFx.Connectors.Tests
|
||||
{
|
||||
|
@ -35,12 +37,19 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
{
|
||||
string outFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\.."));
|
||||
string srcFolder = Path.GetFullPath(Path.Combine(outFolder, ".."));
|
||||
string reportName = @"report\Analysis.txt";
|
||||
string jsonReport = @"report\Report.json";
|
||||
string reportFolder = @"report";
|
||||
string reportName = @$"{reportFolder}\Analysis.txt";
|
||||
string jsonReport = @$"{reportFolder}\Report.json";
|
||||
|
||||
// New report name every second
|
||||
string jsonReport2 = @$"report\Report_{Math.Round(DateTime.UtcNow.Ticks / 1e7):00000000000}.json";
|
||||
|
||||
string outFolderPath = Path.Combine(outFolder, reportFolder);
|
||||
if (Directory.Exists(outFolderPath))
|
||||
{
|
||||
Directory.Delete(outFolderPath, true);
|
||||
}
|
||||
|
||||
// On build servers: ENV: C:\__w\1\s\pfx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Release\netcoreapp3.1
|
||||
// Locally : ENV: C:\Data\Power-Fx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Debug\netcoreapp3.1
|
||||
_output.WriteLine($"ENV: {Environment.CurrentDirectory}");
|
||||
|
@ -48,7 +57,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
_output.WriteLine($"SRC: {srcFolder}");
|
||||
|
||||
Directory.CreateDirectory(Path.Combine(outFolder, "report"));
|
||||
GenerateReport(reportName, outFolder, srcFolder);
|
||||
GenerateReport(reportFolder, reportName, outFolder, srcFolder);
|
||||
AnalyzeReport(reportName, outFolder, srcFolder, jsonReport);
|
||||
|
||||
File.Copy(Path.Combine(outFolder, jsonReport), Path.Combine(outFolder, jsonReport2));
|
||||
|
@ -325,7 +334,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
White = 3, // #FFFFFF
|
||||
}
|
||||
|
||||
private void GenerateReport(string reportName, string outFolder, string srcFolder)
|
||||
private void GenerateReport(string reportFolder, string reportName, string outFolder, string srcFolder)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
@ -359,28 +368,47 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
|
||||
// Check we can add the service (more comprehensive test)
|
||||
config.AddActionConnector("Connector", doc);
|
||||
|
||||
IEnumerable<ConnectorFunction> functions2 = OpenApiParser.GetFunctions(new ConnectorSettings("C1") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc);
|
||||
|
||||
IEnumerable<ConnectorFunction> functions2 = OpenApiParser.GetFunctions(new ConnectorSettings("C1") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc);
|
||||
string cFolder = Path.Combine(outFolder, reportFolder, doc.Info.Title);
|
||||
|
||||
int ix = 2;
|
||||
while (Directory.Exists(cFolder))
|
||||
{
|
||||
cFolder = Path.Combine(outFolder, reportFolder, doc.Info.Title) + $"_{ix++}";
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(cFolder);
|
||||
|
||||
foreach (ConnectorFunction cf1 in functions)
|
||||
{
|
||||
ConnectorFunction cf2 = functions2.First(f => f.Name == cf1.Name);
|
||||
|
||||
string rp1 = string.Join(", ", cf1.RequiredParameters.Select(rp => rp.Name));
|
||||
string rp2 = string.Join(", ", cf2.RequiredParameters.Select(rp => rp.Name));
|
||||
|
||||
if (rp1 != rp2)
|
||||
if (cf1.RequiredParameters != null && cf2.RequiredParameters != null)
|
||||
{
|
||||
string s = $"Function {cf1.Name} - Required parameters are different: [{rp1}] -- [{rp2}]";
|
||||
if (w2.ContainsKey(title))
|
||||
string rp1 = string.Join(", ", cf1.RequiredParameters.Select(rp => rp.Name));
|
||||
string rp2 = string.Join(", ", cf2.RequiredParameters.Select(rp => rp.Name));
|
||||
|
||||
if (rp1 != rp2)
|
||||
{
|
||||
w2[title].Add(s);
|
||||
string s = $"Function {cf1.Name} - Required parameters are different: [{rp1}] -- [{rp2}]";
|
||||
if (w2.ContainsKey(title))
|
||||
{
|
||||
w2[title].Add(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
w2.Add(title, new List<string>() { s });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w2.Add(title, new List<string>() { s });
|
||||
}
|
||||
}
|
||||
|
||||
dynamic obj = cf1.ToExpando(swaggerFile);
|
||||
var serializer = new SerializerBuilder().Build();
|
||||
string yaml = serializer.Serialize(obj);
|
||||
|
||||
string functionFile = Path.Combine(cFolder, cf1.OriginalName.Replace("/", "_") + ".yaml");
|
||||
File.WriteAllText(functionFile, yaml);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -400,7 +428,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
}
|
||||
}
|
||||
|
||||
using StreamWriter writer2 = new StreamWriter(Path.Combine(outFolder, "ConnectorComparison.txt"), append: false);
|
||||
using StreamWriter writer2 = new StreamWriter(Path.Combine(outFolder, reportFolder, "ConnectorComparison.txt"), append: false);
|
||||
|
||||
foreach (KeyValuePair<string, List<string>> kvp in w2.OrderBy(kvp => kvp.Key))
|
||||
{
|
||||
|
@ -509,5 +537,306 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
console.WriteLine(obj.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static ExpandoObject ToExpando(this ConnectorFunction connectorFunction, string swaggerFile)
|
||||
{
|
||||
dynamic func = new ExpandoObject();
|
||||
|
||||
func.Name = connectorFunction.Name;
|
||||
func.OperationId = connectorFunction.OriginalName;
|
||||
func.Method = connectorFunction.HttpMethod.ToString().ToUpperInvariant();
|
||||
func.Path = connectorFunction.OperationPath;
|
||||
func.SwaggerFile = swaggerFile;
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorFunction.Description))
|
||||
{
|
||||
func.Description = connectorFunction.Description;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorFunction.Summary))
|
||||
{
|
||||
func.Summary = connectorFunction.Summary;
|
||||
}
|
||||
|
||||
func.IsBehavior = connectorFunction.IsBehavior;
|
||||
func.IsDeprecated = connectorFunction.IsDeprecated;
|
||||
func.IsInternal = connectorFunction.IsInternal;
|
||||
func.IsPageable = connectorFunction.IsPageable;
|
||||
|
||||
if (connectorFunction.RequiresUserConfirmation)
|
||||
{
|
||||
func.RequiresUserConfirmation = connectorFunction.RequiresUserConfirmation;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorFunction.Visibility))
|
||||
{
|
||||
func.Visibility = connectorFunction.Visibility;
|
||||
}
|
||||
|
||||
func.ReturnType = connectorFunction.ReturnType._type.ToString();
|
||||
func.ReturnType_Detailed = connectorFunction.ConnectorReturnType == null ? (dynamic)"null" : connectorFunction.ConnectorReturnType.ToExpando(noname: true);
|
||||
|
||||
func.ArityMin = connectorFunction.ArityMin;
|
||||
func.ArityMax = connectorFunction.ArityMax;
|
||||
func.RequiredParameters = connectorFunction.RequiredParameters == null ? (dynamic)"null" : connectorFunction.RequiredParameters.Select(rp => rp.ToExpando()).ToList();
|
||||
func.OptionalParameters = connectorFunction.OptionalParameters == null ? (dynamic)"null" : connectorFunction.OptionalParameters.Select(op => op.ToExpando()).ToList();
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this ConnectorParameter connectorParam)
|
||||
{
|
||||
dynamic cParam = new ExpandoObject();
|
||||
|
||||
cParam.Name = connectorParam.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorParam.Description))
|
||||
{
|
||||
cParam.Description = connectorParam.Description;
|
||||
}
|
||||
|
||||
if (connectorParam.Location != null)
|
||||
{
|
||||
cParam.Location = connectorParam.Location.ToString();
|
||||
}
|
||||
|
||||
cParam.FormulaType = connectorParam.FormulaType._type.ToString();
|
||||
cParam.Type = connectorParam.ConnectorType.ToExpando();
|
||||
|
||||
if (connectorParam.DefaultValue != null)
|
||||
{
|
||||
cParam.DefaultValue = connectorParam.DefaultValue.ToExpression();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorParam.Title))
|
||||
{
|
||||
cParam.Title = connectorParam.Title;
|
||||
}
|
||||
|
||||
if (connectorParam.ConnectorExtensions.ExplicitInput)
|
||||
{
|
||||
cParam.ExplicitInput = connectorParam.ConnectorExtensions.ExplicitInput;
|
||||
}
|
||||
|
||||
return cParam;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this ConnectorType connectorType, bool noname = false)
|
||||
{
|
||||
dynamic cType = new ExpandoObject();
|
||||
|
||||
if (!noname)
|
||||
{
|
||||
cType.Name = connectorType.Name;
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorType.DisplayName))
|
||||
{
|
||||
cType.DisplayName = connectorType.DisplayName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(connectorType.Description))
|
||||
{
|
||||
cType.Description = connectorType.Description;
|
||||
}
|
||||
}
|
||||
|
||||
cType.IsRequired = connectorType.IsRequired;
|
||||
|
||||
if (connectorType.Fields != null && connectorType.Fields.Any())
|
||||
{
|
||||
cType.Fields = connectorType.Fields.Select(fieldCT => fieldCT.ToExpando()).ToList();
|
||||
}
|
||||
|
||||
cType.FormulaType = connectorType.FormulaType._type.ToString();
|
||||
|
||||
if (connectorType.ExplicitInput)
|
||||
{
|
||||
cType.ExplicitInput = connectorType.ExplicitInput;
|
||||
}
|
||||
|
||||
cType.IsEnum = connectorType.IsEnum;
|
||||
|
||||
if (connectorType.IsEnum)
|
||||
{
|
||||
bool hasDisplayNames = connectorType.EnumDisplayNames != null && connectorType.EnumDisplayNames.Length > 0;
|
||||
cType.EnumValues = connectorType.EnumValues.Select<FormulaValue, object>((ev, i) => GetEnumExpando(hasDisplayNames ? connectorType.EnumDisplayNames[i] : null, ev.ToObject().ToString(), ev.Type._type.ToString())).ToList();
|
||||
}
|
||||
|
||||
if (connectorType.Visibility != Visibility.None && connectorType.Visibility != Visibility.Unknown)
|
||||
{
|
||||
cType.Visibility = connectorType.Visibility.ToString();
|
||||
}
|
||||
|
||||
if (connectorType.DynamicList != null)
|
||||
{
|
||||
cType.DynamicList = connectorType.DynamicList.ToExpando();
|
||||
}
|
||||
|
||||
if (connectorType.DynamicProperty != null)
|
||||
{
|
||||
cType.DynamicProperty = connectorType.DynamicProperty.ToExpando();
|
||||
}
|
||||
|
||||
if (connectorType.DynamicSchema != null)
|
||||
{
|
||||
cType.DynamicSchema = connectorType.DynamicSchema.ToExpando();
|
||||
}
|
||||
|
||||
if (connectorType.DynamicValues != null)
|
||||
{
|
||||
cType.DynamicValues = connectorType.DynamicValues.ToExpando();
|
||||
}
|
||||
|
||||
return cType;
|
||||
}
|
||||
|
||||
internal static ExpandoObject GetEnumExpando(string displayName, string value, string type)
|
||||
{
|
||||
dynamic e = new ExpandoObject();
|
||||
|
||||
if (!string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
e.DisplayName = displayName;
|
||||
}
|
||||
|
||||
e.Value = value;
|
||||
e.Type = type;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this ConnectorDynamicList dynamicList)
|
||||
{
|
||||
dynamic dList = new ExpandoObject();
|
||||
|
||||
dList.OperationId = dynamicList.OperationId;
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicList.ItemValuePath))
|
||||
{
|
||||
dList.ItemValuePath = dynamicList.ItemValuePath;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicList.ItemPath))
|
||||
{
|
||||
dList.ItemPath = dynamicList.ItemPath;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicList.ItemTitlePath))
|
||||
{
|
||||
dList.ItemTitlePath = dynamicList.ItemTitlePath;
|
||||
}
|
||||
|
||||
if (dynamicList.ParameterMap != null)
|
||||
{
|
||||
dList.Map = dynamicList.ParameterMap.ToExpando();
|
||||
}
|
||||
|
||||
return dList;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this ConnectorDynamicProperty dynamicProp)
|
||||
{
|
||||
dynamic dProp = new ExpandoObject();
|
||||
|
||||
dProp.OperationId = dynamicProp.OperationId;
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicProp.ItemValuePath))
|
||||
{
|
||||
dProp.ItemValuePath = dynamicProp.ItemValuePath;
|
||||
}
|
||||
|
||||
if (dynamicProp.ParameterMap != null)
|
||||
{
|
||||
dProp.Map = dynamicProp.ParameterMap.ToExpando();
|
||||
}
|
||||
|
||||
return dProp;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this ConnectorDynamicSchema dynamicSchema)
|
||||
{
|
||||
dynamic dSchema = new ExpandoObject();
|
||||
|
||||
dSchema.OperationId = dynamicSchema.OperationId;
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicSchema.ValuePath))
|
||||
{
|
||||
dSchema.ValuePath = dynamicSchema.ValuePath;
|
||||
}
|
||||
|
||||
if (dynamicSchema.ParameterMap != null)
|
||||
{
|
||||
dSchema.Map = dynamicSchema.ParameterMap.ToExpando();
|
||||
}
|
||||
|
||||
return dSchema;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this ConnectorDynamicValue dynamicValue)
|
||||
{
|
||||
dynamic dValue = new ExpandoObject();
|
||||
|
||||
dValue.OperationId = dynamicValue.OperationId;
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicValue.ValuePath))
|
||||
{
|
||||
dValue.ValuePath = dynamicValue.ValuePath;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicValue.ValueTitle))
|
||||
{
|
||||
dValue.ValueTitle = dynamicValue.ValueTitle;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(dynamicValue.ValueCollection))
|
||||
{
|
||||
dValue.ValueCollection = dynamicValue.ValueCollection;
|
||||
}
|
||||
|
||||
if (dynamicValue.ParameterMap != null)
|
||||
{
|
||||
dValue.Map = dynamicValue.ParameterMap.ToExpando();
|
||||
}
|
||||
|
||||
return dValue;
|
||||
}
|
||||
|
||||
internal static ExpandoObject ToExpando(this Dictionary<string, IConnectorExtensionValue> paramMap)
|
||||
{
|
||||
IDictionary<string, object> dMap = new ExpandoObject() as IDictionary<string, object>;
|
||||
|
||||
foreach (var kvp in paramMap)
|
||||
{
|
||||
if (kvp.Value is StaticConnectorExtensionValue scev)
|
||||
{
|
||||
dMap[kvp.Key] = GetStaticExt(scev.Value.ToExpression(), scev.Value.Type._type.ToString());
|
||||
}
|
||||
else if (kvp.Value is DynamicConnectorExtensionValue dcev)
|
||||
{
|
||||
dMap[kvp.Key] = GetDynamicExt(dcev.Reference);
|
||||
}
|
||||
}
|
||||
|
||||
return (dynamic)dMap;
|
||||
}
|
||||
|
||||
internal static ExpandoObject GetStaticExt(string value, string type)
|
||||
{
|
||||
dynamic s = new ExpandoObject();
|
||||
|
||||
s.Value = value;
|
||||
s.Type = type;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
internal static ExpandoObject GetDynamicExt(string @ref)
|
||||
{
|
||||
dynamic s = new ExpandoObject();
|
||||
|
||||
s.Reference = @ref;
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
RecordValue rv2 = engine.Eval(@"{a:""x""}") as RecordValue;
|
||||
|
||||
var ex = Assert.Throws<ArgumentException>(() => HttpFunctionInvoker.MergeRecords(rv1, rv2));
|
||||
Assert.Equal("Cannot merge a of type DecimalValue with a of type StringValue", ex.Message);
|
||||
Assert.Equal("Cannot merge 'a' of type DecimalValue with 'a' of type StringValue", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
|
||||
<PackageReference Include="YamlDotNet" Version="13.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
Загрузка…
Ссылка в новой задаче