Skip to content

Commit f865a25

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/Power-Fx into yucl/udf_dataSource_delegatable
2 parents fbb0a07 + 8956f56 commit f865a25

39 files changed

+2675
-1874
lines changed

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

+1,623-1,607
Large diffs are not rendered by default.

src/libraries/Microsoft.PowerFx.Connectors/Execution/FormulaValueSerializer.cs

+22-17
Original file line numberDiff line numberDiff line change
@@ -108,31 +108,36 @@ private async Task WriteObjectAsync(string objectName, ISwaggerSchema schema, IE
108108
await WritePropertyAsync(
109109
nv.Name,
110110
new SwaggerSchema(
111-
type: nv.Value.Type._type.Kind switch
112-
{
113-
DKind.Number => "number",
114-
DKind.Decimal => "number",
115-
DKind.String or
116-
DKind.Date or
117-
DKind.DateTime or
118-
DKind.DateTimeNoTimeZone => "string",
119-
DKind.Boolean => "boolean",
120-
DKind.Record => "object",
121-
DKind.Table => "array",
122-
DKind.ObjNull => "null",
123-
_ => $"type: unknown_dkind {nv.Value.Type._type.Kind}"
124-
},
125-
format: GetDateFormat(nv.Value.Type._type.Kind)),
111+
type: GetType(nv.Value.Type),
112+
format: GetFormat(nv.Value.Type)),
126113
nv.Value).ConfigureAwait(false);
127114
}
128115
}
129116

130117
EndObject(objectName);
131118
}
132119

133-
private static string GetDateFormat(DKind kind)
120+
internal static string GetType(FormulaType type)
134121
{
135-
return kind switch
122+
return type._type.Kind switch
123+
{
124+
DKind.Number => "number",
125+
DKind.Decimal => "number",
126+
DKind.String or
127+
DKind.Date or
128+
DKind.DateTime or
129+
DKind.DateTimeNoTimeZone => "string",
130+
DKind.Boolean => "boolean",
131+
DKind.Record => "object",
132+
DKind.Table => "array",
133+
DKind.ObjNull => "null",
134+
_ => $"type: unknown_dkind {type._type.Kind}"
135+
};
136+
}
137+
138+
internal static string GetFormat(FormulaType type)
139+
{
140+
return type._type.Kind switch
136141
{
137142
DKind.Date => "date",
138143
DKind.DateTime => "date-time",

src/libraries/Microsoft.PowerFx.Connectors/Execution/HttpFunctionInvoker.cs

+19-5
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,28 @@ public async Task<HttpRequestMessage> BuildRequest(FormulaValue[] args, IConvert
5757
// Header names are not case sensitive.
5858
// From RFC 2616 - "Hypertext Transfer Protocol -- HTTP/1.1", Section 4.2, "Message Headers"
5959
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
60-
Dictionary<string, (ISwaggerSchema, FormulaValue)> bodyParts = new ();
60+
Dictionary<string, (ISwaggerSchema, FormulaValue)> bodyParts = new ();
6161
Dictionary<string, FormulaValue> incomingParameters = ConvertToNamedParameters(args);
6262
string contentType = null;
6363

6464
foreach (KeyValuePair<ConnectorParameter, FormulaValue> param in _function._internals.OpenApiBodyParameters)
65-
{
65+
{
6666
if (incomingParameters.TryGetValue(param.Key.Name, out var paramValue))
6767
{
68-
bodyParts.Add(param.Key.Name, (param.Key.Schema, paramValue));
68+
if (_function._internals.SpecialBodyHandling && paramValue is RecordValue rv)
69+
{
70+
foreach (NamedValue field in rv.Fields)
71+
{
72+
string type = FormulaValueSerializer.GetType(field.Value.Type);
73+
string format = FormulaValueSerializer.GetFormat(field.Value.Type);
74+
75+
bodyParts.Add(field.Name, (new SwaggerSchema(type, format), field.Value));
76+
}
77+
}
78+
else
79+
{
80+
bodyParts.Add(param.Key.Name, (param.Key.Schema, paramValue));
81+
}
6982
}
7083
else if (param.Key.Schema.Default != null && param.Value != null)
7184
{
@@ -200,6 +213,7 @@ public Dictionary<string, FormulaValue> ConvertToNamedParameters(FormulaValue[]
200213
// Parameter names are case sensitive.
201214

202215
Dictionary<string, FormulaValue> map = new ();
216+
bool specialBodyHandling = _function._internals.SpecialBodyHandling;
203217

204218
// Seed with default values. This will get overwritten if provided.
205219
foreach (KeyValuePair<string, (bool required, FormulaValue fValue, DType dType)> kv in _function._internals.ParameterDefaultValues)
@@ -217,9 +231,9 @@ public Dictionary<string, FormulaValue> ConvertToNamedParameters(FormulaValue[]
217231
{
218232
string parameterName = _function.RequiredParameters[i].Name;
219233
FormulaValue paramValue = args[i];
220-
234+
221235
// Objects are always flattenned
222-
if (paramValue is RecordValue record && !_function.RequiredParameters[i].IsBodyParameter)
236+
if (paramValue is RecordValue record && (specialBodyHandling || !_function.RequiredParameters[i].IsBodyParameter))
223237
{
224238
foreach (NamedValue field in record.Fields)
225239
{

src/libraries/Microsoft.PowerFx.Connectors/Internal/ConnectorParameterInternals.cs

+2
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,7 @@ internal class ConnectorParameterInternals
2020
internal string BodySchemaReferenceId { get; init; }
2121

2222
internal Dictionary<string, (bool, FormulaValue, DType)> ParameterDefaultValues { get; init; }
23+
24+
internal bool SpecialBodyHandling { get; init; }
2325
}
2426
}

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

+10
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ internal CdpTableValue(IRContext irContext)
4444

4545
public override IEnumerable<DValue<RecordValue>> Rows => GetRowsAsync(null, null, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
4646

47+
public DelegationParameterFeatures SupportedFeatures => DelegationParameterFeatures.Filter |
48+
DelegationParameterFeatures.Top |
49+
DelegationParameterFeatures.Columns | // $select
50+
DelegationParameterFeatures.Sort; // $orderby
51+
4752
public async Task<IReadOnlyCollection<DValue<RecordValue>>> GetRowsAsync(IServiceProvider services, DelegationParameters parameters, CancellationToken cancel)
4853
{
4954
if (parameters == null && _cachedRows != null)
@@ -66,6 +71,11 @@ public void Refresh()
6671
{
6772
_cachedRows = null;
6873
}
74+
75+
public Task<FormulaValue> ExecuteQueryAsync(IServiceProvider services, DelegationParameters parameters, CancellationToken cancel)
76+
{
77+
throw new NotImplementedException();
78+
}
6979
}
7080

7181
internal static class ODataParametersExtensions

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

+9-8
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,17 @@ public bool ExposeInternalParamsWithoutDefaultValue
9292
/// This flag will force all enums to be returns as FormulaType.String or FormulaType.Decimal regardless of x-ms-enum-*.
9393
/// This flag is only in effect when SupportXMsEnumValues is true.
9494
/// </summary>
95-
public bool ReturnEnumsAsPrimitive { get; init; } = false;
96-
95+
public bool ReturnEnumsAsPrimitive { get; init; } = false;
96+
9797
/// <summary>
98-
/// In Power Apps, when a body parameter is used it's flattened and we create one parameter for each
99-
/// body object property. With that logic each parameter name will be the object property name.
100-
/// When set, this setting will use the real body name specified in the swagger instead of the property name
101-
/// of the object, provided there is only one property.
98+
/// This flag enables some special handling for the body parameter, when
99+
/// - body name is 'item'
100+
/// - body inner object is 'dynamicProperties'
101+
/// - there is only one property in inner object
102+
/// In that base the body will be fully flattened and we will retain the 'body' name for the parameter.
102103
/// </summary>
103-
public bool UseDefaultBodyNameForSinglePropertyObject { get; init; } = false;
104-
104+
public bool UseItemDynamicPropertiesSpecialHandling { get; init; } = false;
105+
105106
public ConnectorCompatibility Compatibility { get; init; } = ConnectorCompatibility.Default;
106107
}
107108

src/libraries/Microsoft.PowerFx.Connectors/Texl/ConnectorTexlFunction.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
using Microsoft.PowerFx.Core.Localization;
1313
using Microsoft.PowerFx.Core.Types;
1414
using Microsoft.PowerFx.Core.Utils;
15+
using Microsoft.PowerFx.Functions;
1516
using Microsoft.PowerFx.Intellisense;
1617
using Microsoft.PowerFx.Types;
1718
using static Microsoft.PowerFx.Connectors.ConnectorHelperFunctions;
1819

1920
namespace Microsoft.PowerFx.Connectors
2021
{
21-
internal class ConnectorTexlFunction : TexlFunction, IAsyncConnectorTexlFunction, IHasUnsupportedFunctions
22+
internal class ConnectorTexlFunction : TexlFunction, IFunctionInvoker, IHasUnsupportedFunctions
2223
{
2324
public ConnectorFunction ConnectorFunction { get; }
2425

@@ -85,8 +86,11 @@ public override bool TryGetParamDescription(string paramName, out string paramDe
8586

8687
public override bool HasSuggestionsForParam(int argumentIndex) => argumentIndex <= MaxArity;
8788

88-
public async Task<FormulaValue> InvokeAsync(FormulaValue[] args, IServiceProvider serviceProvider, CancellationToken cancellationToken)
89+
public async Task<FormulaValue> InvokeAsync(FunctionInvokeInfo invokeInfo, CancellationToken cancellationToken)
8990
{
91+
FormulaValue[] args = invokeInfo.Args.ToArray(); // https://github.com/microsoft/Power-Fx/issues/2817
92+
var serviceProvider = invokeInfo.FunctionServices;
93+
9094
cancellationToken.ThrowIfCancellationRequested();
9195
BaseRuntimeConnectorContext runtimeContext = serviceProvider.GetService(typeof(BaseRuntimeConnectorContext)) as BaseRuntimeConnectorContext ?? throw new InvalidOperationException("RuntimeConnectorContext is missing from service provider");
9296

src/libraries/Microsoft.PowerFx.Core/Entities/External/TableDelegationInfo.cs

+51
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public abstract class TableDelegationInfo
2626
[Obsolete("preview")]
2727
public SummarizeCapabilities SummarizeCapabilities { get; init; }
2828

29+
[Obsolete("preview")]
30+
public CountCapabilities CountCapabilities { get; init; }
31+
2932
// Defines ungroupable columns
3033
public GroupRestrictions GroupRestriction { get; init; }
3134

@@ -299,6 +302,54 @@ public enum SummarizeMethod
299302
CountRows
300303
}
301304

305+
[Obsolete("preview")]
306+
public class CountCapabilities
307+
{
308+
public CountCapabilities()
309+
{
310+
}
311+
312+
/// <summary>
313+
/// If the table is countable, return true.
314+
/// Relevant expression: CountRows(Table).
315+
/// </summary>
316+
/// <returns></returns>
317+
public virtual bool IsCountableTable()
318+
{
319+
return false;
320+
}
321+
322+
/// <summary>
323+
/// If the table is countable after filter, return true.
324+
/// Relevant expression: CountRows(Filter(Table, Condition)); / CountIf(Table, Condition).
325+
/// </summary>
326+
/// <returns></returns>
327+
public virtual bool IsCountableAfterFilter()
328+
{
329+
return false;
330+
}
331+
332+
/// <summary>
333+
/// If the table is countable after join, return true.
334+
/// Relevant expression: CountRows(Join(Table1, Table2, ...)).
335+
/// </summary>
336+
/// <returns></returns>
337+
public virtual bool IsCountableAfterJoin()
338+
{
339+
return false;
340+
}
341+
342+
/// <summary>
343+
/// If the table is countable after summarize, return true.
344+
/// Relevant expression: CountRows(Summarize(Table, ...)).
345+
/// </summary>
346+
/// <returns></returns>
347+
public virtual bool IsCountableAfterSummarize()
348+
{
349+
return false;
350+
}
351+
}
352+
302353
public sealed class FilterRestrictions
303354
{
304355
// List of required properties

src/libraries/Microsoft.PowerFx.Core/Functions/IAsyncTexlFunction.cs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Microsoft.PowerFx.Core.Functions
99
{
1010
// A Texl function capable of async invokes.
11+
// This only lives in Core to enable Fx.Json funcs impl (which doesn't depend on interpreter).
1112
internal interface IAsyncTexlFunction
1213
{
1314
Task<FormulaValue> InvokeAsync(FormulaValue[] args, CancellationToken cancellationToken);

src/libraries/Microsoft.PowerFx.Core/Functions/IAsyncTexlFunction3.cs

-16
This file was deleted.

src/libraries/Microsoft.PowerFx.Core/Functions/IAsyncTexlFunction4.cs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace Microsoft.PowerFx.Core.Functions
1010
{
1111
// A Texl function capable of async invokes, using TimeZoneInfo and IRContext.
12+
// Remove this: https://github.com/microsoft/Power-Fx/issues/2818
1213
internal interface IAsyncTexlFunction4
1314
{
1415
Task<FormulaValue> InvokeAsync(TimeZoneInfo timezoneInfo, FormulaType irContext, FormulaValue[] args, CancellationToken cancellationToken);

src/libraries/Microsoft.PowerFx.Core/Functions/IAsyncTexlFunction5.cs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
using Microsoft.PowerFx.Types;
88

99
namespace Microsoft.PowerFx.Core.Functions
10-
{
10+
{
1111
// Texl function interface with IServiceProvider
12+
// Only product impl is JsonFunctionImpl.
13+
// Remove this: https://github.com/microsoft/Power-Fx/issues/2818
1214
internal interface IAsyncTexlFunction5
1315
{
1416
Task<FormulaValue> InvokeAsync(IServiceProvider runtimeServiceProvider, FormulaType irContext, FormulaValue[] args, CancellationToken cancellationToken);

src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs

+1
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ internal static class TexlStrings
692692
public static ErrorResourceKey ErrCannotCoerce_SourceType_TargetType = new ErrorResourceKey("ErrCannotCoerce_SourceType_TargetType");
693693
public static ErrorResourceKey ErrNumberOrStringExpected = new ErrorResourceKey("ErrNumberOrStringExpected");
694694
public static ErrorResourceKey ErrClosingBracketExpected = new ErrorResourceKey("ErrClosingBracketExpected");
695+
public static ErrorResourceKey ErrClosingIdentifierExpected = new ErrorResourceKey("ErrClosingIdentifierExpected");
695696
public static ErrorResourceKey ErrEmptyInvalidIdentifier = new ErrorResourceKey("ErrEmptyInvalidIdentifier");
696697
public static ErrorResourceKey ErrIncompatibleTypes = new ErrorResourceKey("ErrIncompatibleTypes");
697698
public static ErrorResourceKey ErrIncompatibleTypesForEquality_Left_Right = new ErrorResourceKey("ErrIncompatibleTypesForEquality_Left_Right");

src/libraries/Microsoft.PowerFx.Core/Parser/TexlParser.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1429,13 +1429,13 @@ private Identifier ParseIdentifier(Token at = null)
14291429
if (_curs.TidCur == TokKind.Ident)
14301430
{
14311431
tok = _curs.TokMove().As<IdentToken>();
1432-
if (tok.HasDelimiterStart && !tok.HasDelimiterEnd)
1432+
if (tok.IsModified)
14331433
{
1434-
PostError(tok, TexlStrings.ErrClosingBracketExpected);
1434+
PostError(tok, TexlStrings.ErrEmptyInvalidIdentifier);
14351435
}
1436-
else if (tok.IsModified)
1436+
else if (tok.HasDelimiterStart && !tok.HasDelimiterEnd)
14371437
{
1438-
PostError(tok, TexlStrings.ErrEmptyInvalidIdentifier);
1438+
PostError(tok, TexlStrings.ErrClosingIdentifierExpected);
14391439
}
14401440
}
14411441
else

src/libraries/Microsoft.PowerFx.Core/Public/Config/PowerFxConfig.cs

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public SymbolTable SymbolTable
5252
set => _symbolTable = value;
5353
}
5454

55+
// Remove this: https://github.com/microsoft/Power-Fx/issues/2821
5556
internal readonly Dictionary<TexlFunction, IAsyncTexlFunction> AdditionalFunctions = new ();
5657

5758
[Obsolete("Use Config.EnumStore or symboltable directly")]

src/libraries/Microsoft.PowerFx.Core/Public/Values/DelegationParameters.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ public enum DelegationParameterFeatures
7676
// $apply = groupby((field1, ..), field with sum as TotalSum)
7777
ApplyGroupBy = 1 << 5,
7878

79+
// $count
80+
Count = 1 << 6,
81+
7982
/*
8083
To be implemented later when needed
8184
8285
// $compute
8386
Compute = 1 << 5,
8487
85-
// $count
86-
Count = 1 << 6,
87-
8888
// $expand
8989
Expand = 1 << 7,
9090

src/libraries/Microsoft.PowerFx.Core/Public/Values/TableValue.cs

+14
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,21 @@ public interface IDelegatableTableValue
2727
/// <param name="parameters">delegation parameters.</param>
2828
/// <param name="cancel"></param>
2929
/// <returns></returns>
30+
[Obsolete($"Use {nameof(ExecuteQueryAsync)} instead.")]
3031
Task<IReadOnlyCollection<DValue<RecordValue>>> GetRowsAsync(IServiceProvider services, DelegationParameters parameters, CancellationToken cancel);
32+
33+
/// <summary>
34+
/// Evaluation will invoke this method on aggregation calls where return value is scaler.
35+
/// </summary>
36+
/// <param name="services">Pre-eval services.</param>
37+
/// <param name="parameters">Delegation parameters.</param>
38+
/// <param name="cancel"></param>
39+
Task<FormulaValue> ExecuteQueryAsync(IServiceProvider services, DelegationParameters parameters, CancellationToken cancel);
40+
41+
/// <summary>
42+
/// Supported features for delegation to verify correct Features are delegated at runtime.
43+
/// </summary>
44+
DelegationParameterFeatures SupportedFeatures { get; }
3145
}
3246

3347
/// <summary>

0 commit comments

Comments
 (0)