Skip to content

Commit f0af967

Browse files
authored
Add ReturnEnumsAsPrimitive connector settings (#2807)
When SupportXMsEnumValues is set to true, we want to force 'modelAsString' to false via ReturnEnumsAsPrimitive flag This will keep the x-ms-enum-* extensions to be parsed while creating a consistent FormulaType as string or decimal
1 parent a957fcd commit f0af967

File tree

4 files changed

+116
-45
lines changed

4 files changed

+116
-45
lines changed

src/libraries/Microsoft.PowerFx.Connectors/OpenApiExtensions.cs

+10
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,11 @@ private static ConnectorType TryGetOptionSet(ISwaggerParameter openApiParameter,
716716
return new ConnectorType(schema, openApiParameter, FormulaType.String, list: list, isNumber: isNumber);
717717
}
718718

719+
if (settings.Settings.ReturnEnumsAsPrimitive)
720+
{
721+
return new ConnectorType(schema, openApiParameter, isNumber ? FormulaType.Decimal : FormulaType.String, list: list, isNumber: isNumber);
722+
}
723+
719724
return new ConnectorType(schema, openApiParameter, optionSet.FormulaType);
720725
}
721726

@@ -737,6 +742,11 @@ private static ConnectorType TryGetOptionSet(ISwaggerParameter openApiParameter,
737742
return new ConnectorType(schema, openApiParameter, FormulaType.String, list: dic);
738743
}
739744

745+
if (settings.Settings.ReturnEnumsAsPrimitive)
746+
{
747+
return new ConnectorType(schema, openApiParameter, isNumber ? FormulaType.Decimal : FormulaType.String, list: list, isNumber: isNumber);
748+
}
749+
740750
return new ConnectorType(schema, openApiParameter, optionSet.FormulaType);
741751
}
742752
else

src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSettings.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public class ConnectorSettings
1414
internal static readonly ConnectorSettings DefaultCdp = new ConnectorSettings(null)
1515
{
1616
Compatibility = ConnectorCompatibility.CdpCompatibility,
17-
SupportXMsEnumValues = true
17+
SupportXMsEnumValues = true,
18+
ReturnEnumsAsPrimitive = false
1819
};
1920

2021
public ConnectorSettings(string @namespace)
@@ -85,7 +86,13 @@ public bool ExposeInternalParamsWithoutDefaultValue
8586
/// By default action connectors won't parse x-ms-enum-values.
8687
/// Only CDP connectors will have this enabled by default.
8788
/// </summary>
88-
public bool SupportXMsEnumValues { get; init; } = false;
89+
public bool SupportXMsEnumValues { get; init; } = false;
90+
91+
/// <summary>
92+
/// This flag will force all enums to be returns as FormulaType.String or FormulaType.Decimal regardless of x-ms-enum-*.
93+
/// This flag is only in effect when SupportXMsEnumValues is true.
94+
/// </summary>
95+
public bool ReturnEnumsAsPrimitive { get; init; } = false;
8996

9097
public ConnectorCompatibility Compatibility { get; init; } = ConnectorCompatibility.Default;
9198
}

src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ internal ConnectorType(ISwaggerSchema schema, ISwaggerParameter openApiParameter
162162
{
163163
if (list != null && list.Any())
164164
{
165-
EnumValues = list.Select<KeyValuePair<DName, DName>, FormulaValue>(kvp => isNumber ? FormulaValue.New(decimal.Parse(kvp.Value.Value, CultureInfo.InvariantCulture)) : FormulaValue.New(kvp.Value)).ToArray();
166-
EnumDisplayNames = list.Select(list => list.Key.Value).ToArray();
165+
EnumValues = list.Select<KeyValuePair<DName, DName>, FormulaValue>(kvp => isNumber ? FormulaValue.New(decimal.Parse(kvp.Key.Value, CultureInfo.InvariantCulture)) : FormulaValue.New(kvp.Key)).ToArray();
166+
EnumDisplayNames = list.Select(list => list.Value.Value).ToArray();
167167
}
168168
else
169169
{

src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs

+95-41
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,30 @@ private static void AssertEqual(string expected, string actual)
4646
}
4747

4848
[Theory]
49-
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true)]
50-
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false)]
51-
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true)]
52-
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false)]
53-
[InlineData(ConnectorCompatibility.CdpCompatibility, true)]
54-
[InlineData(ConnectorCompatibility.CdpCompatibility, false)]
55-
public void MSNWeather_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues)
49+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true, false)]
50+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false, false)]
51+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true, true)]
52+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false, true)]
53+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, false)]
54+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, false)]
55+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, true)]
56+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, true)]
57+
[InlineData(ConnectorCompatibility.CdpCompatibility, true, false)]
58+
[InlineData(ConnectorCompatibility.CdpCompatibility, false, false)]
59+
[InlineData(ConnectorCompatibility.CdpCompatibility, true, true)]
60+
[InlineData(ConnectorCompatibility.CdpCompatibility, false, true)]
61+
public void MSNWeather_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues, bool returnEnumsAsPrimitive)
5662
{
5763
using var testConnector = new LoggingTestServer(@"Swagger\MSNWeather.json", _output);
58-
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(new ConnectorSettings("MSNWeather") { Compatibility = connectorCompatibility, SupportXMsEnumValues = supportXMsEnumValues }, testConnector._apiDocument).ToList();
64+
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(
65+
new ConnectorSettings("MSNWeather")
66+
{
67+
Compatibility = connectorCompatibility,
68+
SupportXMsEnumValues = supportXMsEnumValues,
69+
ReturnEnumsAsPrimitive = returnEnumsAsPrimitive
70+
},
71+
testConnector._apiDocument).ToList();
72+
5973
ConnectorFunction currentWeather = functions.First(f => f.Name == "CurrentWeather");
6074

6175
Assert.Equal(2, currentWeather.RequiredParameters.Length);
@@ -69,35 +83,56 @@ public void MSNWeather_OptionSets(ConnectorCompatibility connectorCompatibility,
6983

7084
if (connectorCompatibility == ConnectorCompatibility.CdpCompatibility || supportXMsEnumValues)
7185
{
72-
Assert.Equal(FormulaType.OptionSetValue, currentWeather.RequiredParameters[1].FormulaType);
86+
if (returnEnumsAsPrimitive)
87+
{
88+
Assert.Equal(FormulaType.String, currentWeather.RequiredParameters[1].FormulaType);
89+
}
90+
else
91+
{
92+
Assert.Equal(FormulaType.OptionSetValue, currentWeather.RequiredParameters[1].FormulaType);
93+
}
7394

7495
// Dictionary is used here, so we need to reorder
7596
Assert.Equal("Imperial,Metric", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.Enum.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Key)));
7697
Assert.Equal("I,C", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.Enum.OrderBy(kvp => kvp.Key).Select(kvp => (kvp.Value as StringValue).Value)));
7798

78-
Assert.Equal("Imperial,Metric", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.EnumDisplayNames));
99+
Assert.Equal("Imperial,Metric", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.EnumDisplayNames));
79100
}
80101
else
81102
{
82-
Assert.Equal(FormulaType.String, currentWeather.RequiredParameters[1].FormulaType);
103+
Assert.Equal(FormulaType.String, currentWeather.RequiredParameters[1].FormulaType);
83104
}
84105

85106
Assert.Equal("I,C", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.EnumValues.Select(fv => (fv as StringValue).Value)));
86107
}
87108

88109
[Theory]
89-
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true)]
90-
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false)]
91-
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true)]
92-
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false)]
93-
[InlineData(ConnectorCompatibility.CdpCompatibility, true)]
94-
[InlineData(ConnectorCompatibility.CdpCompatibility, false)]
110+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true, false)]
111+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false, false)]
112+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true, true)]
113+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false, true)]
114+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, false)]
115+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, false)]
116+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, true)]
117+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, true)]
118+
[InlineData(ConnectorCompatibility.CdpCompatibility, true, false)]
119+
[InlineData(ConnectorCompatibility.CdpCompatibility, false, false)]
120+
[InlineData(ConnectorCompatibility.CdpCompatibility, true, true)]
121+
[InlineData(ConnectorCompatibility.CdpCompatibility, false, true)]
95122

96123
// Option set with numeric logical names
97-
public void DimeScheduler_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues)
124+
public void DimeScheduler_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues, bool returnEnumsAsPrimitive)
98125
{
99126
using var testConnector = new LoggingTestServer(@"Swagger\Dime.Scheduler.json", _output);
100-
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(new ConnectorSettings("DimeScheduler") { Compatibility = connectorCompatibility, SupportXMsEnumValues = supportXMsEnumValues }, testConnector._apiDocument).ToList();
127+
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(
128+
new ConnectorSettings("DimeScheduler")
129+
{
130+
Compatibility = connectorCompatibility,
131+
SupportXMsEnumValues = supportXMsEnumValues,
132+
ReturnEnumsAsPrimitive = returnEnumsAsPrimitive
133+
},
134+
testConnector._apiDocument).ToList();
135+
101136
ConnectorFunction actionUriUpsert = functions.First(f => f.Name == "actionUriUpsert");
102137

103138
Assert.Equal(5, actionUriUpsert.OptionalParameters.Length);
@@ -106,35 +141,54 @@ public void DimeScheduler_OptionSets(ConnectorCompatibility connectorCompatibili
106141

107142
if (connectorCompatibility == ConnectorCompatibility.CdpCompatibility || supportXMsEnumValues)
108143
{
109-
Assert.Equal(FormulaType.OptionSetValue, actionUriUpsert.OptionalParameters[2].FormulaType);
144+
if (returnEnumsAsPrimitive)
145+
{
146+
Assert.Equal(FormulaType.Decimal, actionUriUpsert.OptionalParameters[2].FormulaType);
147+
}
148+
else
149+
{
150+
Assert.Equal(FormulaType.OptionSetValue, actionUriUpsert.OptionalParameters[2].FormulaType);
151+
}
110152

111153
// Dictionary is used here, so we need to reorder
112154
Assert.Equal("Planning Board,Appointment,Task,Map", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.Enum.Select(kvp => kvp.Key)));
113155
Assert.Equal("0,1,2,3", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.Enum.Select(kvp => (kvp.Value as DecimalValue).Value)));
114156

115-
Assert.Equal("Planning Board,Appointment,Task,Map", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.EnumDisplayNames));
157+
Assert.Equal("Planning Board,Appointment,Task,Map", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.EnumDisplayNames));
116158
}
117159
else
118160
{
119-
Assert.Equal(FormulaType.Decimal, actionUriUpsert.OptionalParameters[2].FormulaType);
161+
Assert.Equal(FormulaType.Decimal, actionUriUpsert.OptionalParameters[2].FormulaType);
120162
}
121163

122164
Assert.Equal("0,1,2,3", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.EnumValues.Select(fv => (fv as DecimalValue).Value)));
123165
}
124166

125167
[Theory]
126-
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true)]
127-
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false)]
128-
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true)]
129-
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false)]
130-
[InlineData(ConnectorCompatibility.CdpCompatibility, true)]
131-
[InlineData(ConnectorCompatibility.CdpCompatibility, false)]
132-
133-
// Option set with numeric logical names
134-
public void ACSL_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues)
168+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true, false)]
169+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false, false)]
170+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, true, true)]
171+
[InlineData(ConnectorCompatibility.SwaggerCompatibility, false, true)]
172+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, false)]
173+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, false)]
174+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, true)]
175+
[InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, true)]
176+
[InlineData(ConnectorCompatibility.CdpCompatibility, true, false)]
177+
[InlineData(ConnectorCompatibility.CdpCompatibility, false, false)]
178+
[InlineData(ConnectorCompatibility.CdpCompatibility, true, true)]
179+
[InlineData(ConnectorCompatibility.CdpCompatibility, false, true)]
180+
public void ACSL_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues, bool returnEnumsAsPrimitive)
135181
{
136182
using var testConnector = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language v2.2.json", _output);
137-
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = connectorCompatibility, SupportXMsEnumValues = supportXMsEnumValues }, testConnector._apiDocument).ToList();
183+
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(
184+
new ConnectorSettings("ACSL")
185+
{
186+
Compatibility = connectorCompatibility,
187+
SupportXMsEnumValues = supportXMsEnumValues,
188+
ReturnEnumsAsPrimitive = returnEnumsAsPrimitive
189+
},
190+
testConnector._apiDocument).ToList();
191+
138192
ConnectorFunction analyzeConversationTranscriptSubmitJob = functions.Single(f => f.Name == "AnalyzeConversationTranscriptSubmitJob");
139193

140194
// AnalyzeConversationTranscript_SubmitJob defined at line 1226 of swagger file
@@ -143,19 +197,19 @@ public void ACSL_OptionSets(ConnectorCompatibility connectorCompatibility, bool
143197
// conversations parameter at line 2577, defined at line 2580(TranscriptConversation)
144198
// conversationItems parameter at line 2585, defined at line 2624(TranscriptConversationItem)
145199
// role parameter at line 2641 is having extension x-ms-enum with modelAsString set to true
146-
ConnectorType connectorType = analyzeConversationTranscriptSubmitJob.RequiredParameters[0].ConnectorType;
200+
ConnectorType connectorType = analyzeConversationTranscriptSubmitJob.RequiredParameters[0].ConnectorType;
147201
ConnectorType role = connectorType.Fields[0].Fields[0].Fields[0].Fields[connectorCompatibility == ConnectorCompatibility.Default ? 4 : 3];
148202
Assert.Equal("role", role.Name);
149203

150204
// Type is always a string here as to be an optionset, we need (ConnectorCompatibility = CdpCompatibility or SupportXMsEnumValues = true) AND (modelAsString = false)
151205
Assert.Equal(FormulaType.String, role.FormulaType);
152206
Assert.True(role.IsEnum);
153-
207+
154208
Assert.Equal<object>(
155209
connectorCompatibility != ConnectorCompatibility.Default
156210
? "![conversations:![conversationItems:*[audioTimings:*[duration:w, offset:w, word:s], id:s, itn:s, language:s, lexical:s, maskedItn:s, participantId:s, role:s, text:s], domain:s, language:s]]"
157-
: "![conversations:![conversationItems:*[audioTimings:*[duration:w, offset:w, word:s], id:s, itn:s, language:s, lexical:s, maskedItn:s, modality:s, participantId:s, role:s, text:s], domain:s, language:s]]",
158-
connectorType.FormulaType._type.ToString());
211+
: "![conversations:![conversationItems:*[audioTimings:*[duration:w, offset:w, word:s], id:s, itn:s, language:s, lexical:s, maskedItn:s, modality:s, participantId:s, role:s, text:s], domain:s, language:s]]",
212+
connectorType.FormulaType._type.ToString());
159213

160214
if (connectorCompatibility == ConnectorCompatibility.CdpCompatibility || supportXMsEnumValues)
161215
{
@@ -1969,16 +2023,16 @@ public async Task SendEmail()
19692023
public async Task AiSensitivityTest()
19702024
{
19712025
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SendMail.json", _output);
1972-
OpenApiDocument apiDoc = testConnector._apiDocument;
1973-
2026+
OpenApiDocument apiDoc = testConnector._apiDocument;
2027+
19742028
ConnectorSettings connectorSettings = new ConnectorSettings("exob")
1975-
{
2029+
{
19762030
Compatibility = ConnectorCompatibility.SwaggerCompatibility,
19772031
AllowUnsupportedFunctions = true,
19782032
IncludeInternalFunctions = true,
1979-
ReturnUnknownRecordFieldsAsUntypedObjects = true
2033+
ReturnUnknownRecordFieldsAsUntypedObjects = true
19802034
};
1981-
2035+
19822036
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(connectorSettings, apiDoc).OrderBy(f => f.Name).ToList();
19832037

19842038
ConnectorFunction sendmail = functions.First(f => f.Name == "SendEmailV3");

0 commit comments

Comments
 (0)