зеркало из https://github.com/microsoft/Power-Fx.git
Merge branch 'main' into lucgen/zd2
This commit is contained in:
Коммит
d0719bd721
|
@ -30,6 +30,12 @@
|
|||
`IsType(UntypedObject, Type)`\
|
||||
`AsType(UntypedObject, Type)`
|
||||
|
||||
## Updated function behaviors:
|
||||
- TimeValue function (https://github.com/microsoft/Power-Fx/pull/2731)
|
||||
- Support for am/pm designators: `TimeValue("6:00pm")` now works (used to return an error)
|
||||
- Better validation: `TimeValue("1")` would return a time value (equivalent to `Time(0,0,0)`), now returns an error
|
||||
- Better support for wrapping times around the 24-hour mark: `TimeValue("27:00:00")` now returns the same as `Time(3,0,0)`, consistent with Excel's behavior.
|
||||
|
||||
## Other:
|
||||
- Untyped object
|
||||
- Read a field from an untyped object by index (https://github.com/microsoft/Power-Fx/pull/2555):
|
||||
|
|
|
@ -28,6 +28,8 @@ using Microsoft.PowerFx.Intellisense;
|
|||
using Microsoft.PowerFx.Types;
|
||||
using static Microsoft.PowerFx.Connectors.ConnectorHelperFunctions;
|
||||
|
||||
#pragma warning disable SA1117
|
||||
|
||||
namespace Microsoft.PowerFx.Connectors
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -294,7 +296,8 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
private readonly ConnectorLogger _configurationLogger = null;
|
||||
|
||||
internal ConnectorFunction(OpenApiOperation openApiOperation, bool isSupported, string notSupportedReason, string name, string operationPath, HttpMethod httpMethod, ConnectorSettings connectorSettings, List<ConnectorFunction> functionList, ConnectorLogger configurationLogger, IReadOnlyDictionary<string, FormulaValue> globalValues)
|
||||
internal ConnectorFunction(OpenApiOperation openApiOperation, bool isSupported, string notSupportedReason, string name, string operationPath, HttpMethod httpMethod, ConnectorSettings connectorSettings, List<ConnectorFunction> functionList,
|
||||
ConnectorLogger configurationLogger, IReadOnlyDictionary<string, FormulaValue> globalValues)
|
||||
{
|
||||
Operation = openApiOperation;
|
||||
Name = name;
|
||||
|
@ -1007,7 +1010,8 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
// Only called by ConnectorTable.GetSchema
|
||||
// Returns a FormulaType with AssociatedDataSources set (done in AddTabularDataSource)
|
||||
internal static ConnectorType GetCdpTableType(ICdpTableResolver tableResolver, string connectorName, string valuePath, StringValue stringValue, List<SqlRelationship> sqlRelationships, ConnectorCompatibility compatibility, string datasetName, out string name, out string displayName, out TableDelegationInfo delegationInfo)
|
||||
internal static ConnectorType GetCdpTableType(ICdpTableResolver tableResolver, string connectorName, string tableName, string valuePath, StringValue stringValue, List<SqlRelationship> sqlRelationships, ConnectorCompatibility compatibility, string datasetName,
|
||||
out string name, out string displayName, out TableDelegationInfo delegationInfo, out IEnumerable<OptionSet> optionSets)
|
||||
{
|
||||
// There are some errors when parsing this Json payload but that's not a problem here as we only need x-ms-capabilities parsing to work
|
||||
OpenApiReaderSettings oars = new OpenApiReaderSettings() { RuleSet = DefaultValidationRuleSet };
|
||||
|
@ -1020,8 +1024,10 @@ namespace Microsoft.PowerFx.Connectors
|
|||
bool isTableReadOnly = tablePermission == ConnectorPermission.PermissionReadOnly;
|
||||
IList<ReferencedEntity> referencedEntities = GetReferenceEntities(connectorName, stringValue);
|
||||
|
||||
ConnectorType connectorType = new ConnectorType(jsonElement, compatibility, sqlRelationships, referencedEntities, datasetName, name, connectorName, tableResolver, serviceCapabilities, isTableReadOnly);
|
||||
SymbolTable symbolTable = new SymbolTable();
|
||||
ConnectorType connectorType = new ConnectorType(jsonElement, tableName, symbolTable, compatibility, sqlRelationships, referencedEntities, datasetName, name, connectorName, tableResolver, serviceCapabilities, isTableReadOnly);
|
||||
delegationInfo = ((DataSourceInfo)connectorType.FormulaType._type.AssociatedDataSources.First()).DelegationInfo;
|
||||
optionSets = symbolTable.OptionSets.Select(kvp => kvp.Value);
|
||||
|
||||
return connectorType;
|
||||
}
|
||||
|
|
|
@ -283,6 +283,10 @@ namespace Microsoft.PowerFx.Connectors.Execution
|
|||
{
|
||||
await WriteBlobValueAsync(bv).ConfigureAwait(false);
|
||||
}
|
||||
else if (fv is OptionSetValue optionSetValue)
|
||||
{
|
||||
WriteStringValue(optionSetValue.Option);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PowerFxConnectorException($"Expected StringValue and got {fv?.GetType()?.Name ?? "<null>"} value, for property {propertyName}");
|
||||
|
|
|
@ -10,6 +10,9 @@ using System.Net.Http;
|
|||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Interfaces;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.PowerFx.Core;
|
||||
using Microsoft.PowerFx.Core.Binding;
|
||||
using Microsoft.PowerFx.Core.Binding.BindInfo;
|
||||
using Microsoft.PowerFx.Core.IR;
|
||||
using Microsoft.PowerFx.Core.Utils;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
@ -82,45 +85,58 @@ namespace Microsoft.PowerFx.Connectors
|
|||
}
|
||||
|
||||
// Get suggested options values. Returns null if none.
|
||||
internal static (string[] options, ConnectorErrors errors) GetOptions(this OpenApiParameter openApiParameter)
|
||||
internal static DisplayNameProvider GetEnumValues(this ISwaggerParameter openApiParameter)
|
||||
{
|
||||
ConnectorErrors errors = new ConnectorErrors();
|
||||
|
||||
// x-ms-enum-values is: array of { value: string, displayName: string}.
|
||||
if (openApiParameter.Extensions.TryGetValue(XMsEnumValues, out var enumValues))
|
||||
{
|
||||
if (enumValues is IList<IOpenApiAny> array)
|
||||
{
|
||||
var list = new List<string>(array.Count);
|
||||
SingleSourceDisplayNameProvider displayNameProvider = new SingleSourceDisplayNameProvider();
|
||||
|
||||
foreach (var item in array)
|
||||
{
|
||||
string logical = null;
|
||||
string display = null;
|
||||
|
||||
if (item is IDictionary<string, IOpenApiAny> obj)
|
||||
{
|
||||
// has keys, "value", and "displayName"
|
||||
if (obj.TryGetValue("value", out IOpenApiAny value))
|
||||
if (obj.TryGetValue("value", out IOpenApiAny openApiLogical))
|
||||
{
|
||||
if (value is OpenApiString str)
|
||||
if (openApiLogical is OpenApiString logicalStr)
|
||||
{
|
||||
list.Add(str.Value);
|
||||
continue;
|
||||
logical = logicalStr.Value;
|
||||
}
|
||||
else if (value is OpenApiInteger i)
|
||||
else if (openApiLogical is OpenApiInteger logicalInt)
|
||||
{
|
||||
list.Add(i.Value.ToString(CultureInfo.InvariantCulture));
|
||||
continue;
|
||||
logical = logicalInt.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.TryGetValue("displayName", out IOpenApiAny openApiDisplay))
|
||||
{
|
||||
if (openApiDisplay is OpenApiString displayStr)
|
||||
{
|
||||
display = displayStr.Value;
|
||||
}
|
||||
else if (openApiDisplay is OpenApiInteger displayInt)
|
||||
{
|
||||
display = displayInt.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(logical) && !string.IsNullOrEmpty(display))
|
||||
{
|
||||
displayNameProvider = displayNameProvider.AddField(new DName(logical), new DName(display));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errors.AddError($"Unrecognized {XMsEnumValues} schema ({item.GetType().Name})");
|
||||
}
|
||||
|
||||
return (list.ToArray(), errors);
|
||||
return displayNameProvider.LogicalToDisplayPairs.Any() ? displayNameProvider : null;
|
||||
}
|
||||
}
|
||||
|
||||
return (null, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsTrigger(this OpenApiOperation op)
|
||||
|
@ -378,11 +394,17 @@ namespace Microsoft.PowerFx.Connectors
|
|||
internal readonly IList<SqlRelationship> SqlRelationships;
|
||||
internal Stack<string> Chain = new Stack<string>();
|
||||
internal int Level = 0;
|
||||
internal readonly SymbolTable OptionSets;
|
||||
|
||||
internal ConnectorTypeGetterSettings(ConnectorCompatibility connectorCompatibility, IList<SqlRelationship> sqlRelationships = null)
|
||||
private readonly string _tableName;
|
||||
|
||||
internal ConnectorTypeGetterSettings(ConnectorCompatibility connectorCompatibility, string tableName, SymbolTable optionSets, IList<SqlRelationship> sqlRelationships = null)
|
||||
{
|
||||
Compatibility = connectorCompatibility;
|
||||
OptionSets = optionSets;
|
||||
SqlRelationships = sqlRelationships;
|
||||
|
||||
_tableName = tableName;
|
||||
}
|
||||
|
||||
internal ConnectorTypeGetterSettings Stack(string identifier)
|
||||
|
@ -397,11 +419,33 @@ namespace Microsoft.PowerFx.Connectors
|
|||
Chain.Pop();
|
||||
Level--;
|
||||
}
|
||||
|
||||
// by default, optionset names will be 'propertyName (tableName)' in CDP case, where propertyName is replaced by x-ms-enum content, when provided
|
||||
// in non-CDP case, tableName is null and will only be 'propertyName' (or x-ms-enum content)
|
||||
internal string GetOptionSetName(string optionSetNameBase)
|
||||
{
|
||||
string optionSetName = optionSetNameBase;
|
||||
|
||||
if (!string.IsNullOrEmpty(_tableName))
|
||||
{
|
||||
optionSetName += $" ({_tableName})";
|
||||
}
|
||||
|
||||
return optionSetName;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiParameter, ConnectorCompatibility compatibility, IList<SqlRelationship> sqlRelationships = null)
|
||||
{
|
||||
return openApiParameter.GetConnectorType(new ConnectorTypeGetterSettings(compatibility, sqlRelationships));
|
||||
return openApiParameter.GetConnectorType(tableName: null, optionSets: null, compatibility, sqlRelationships);
|
||||
}
|
||||
|
||||
internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiParameter, string tableName, SymbolTable optionSets, ConnectorCompatibility compatibility, IList<SqlRelationship> sqlRelationships = null)
|
||||
{
|
||||
ConnectorTypeGetterSettings settings = new ConnectorTypeGetterSettings(compatibility, tableName, optionSets, sqlRelationships);
|
||||
ConnectorType connectorType = openApiParameter.GetConnectorType(settings);
|
||||
|
||||
return connectorType;
|
||||
}
|
||||
|
||||
// See https://swagger.io/docs/specification/data-models/data-types/
|
||||
|
@ -445,12 +489,25 @@ namespace Microsoft.PowerFx.Connectors
|
|||
return new ConnectorType(schema, openApiParameter, FormulaType.Blob);
|
||||
}
|
||||
|
||||
// Try getting enum from 'x-ms-enum-values'
|
||||
DisplayNameProvider optionSetDisplayNameProvider = openApiParameter.GetEnumValues();
|
||||
|
||||
if (optionSetDisplayNameProvider != null && (settings.Compatibility.IsCDP() || schema.Format == "enum"))
|
||||
{
|
||||
string optionSetName = settings.GetOptionSetName(schema.GetEnumName() ?? openApiParameter.Name);
|
||||
OptionSet optionSet = new OptionSet(optionSetName, optionSetDisplayNameProvider);
|
||||
optionSet = settings.OptionSets.TryAddOptionSet(optionSet);
|
||||
return new ConnectorType(schema, openApiParameter, optionSet.FormulaType);
|
||||
}
|
||||
|
||||
// Try getting enum from 'enum'
|
||||
if (schema.Enum != null && (settings.Compatibility.IsCDP() || schema.Format == "enum"))
|
||||
{
|
||||
if (schema.Enum.All(e => e is OpenApiString))
|
||||
{
|
||||
string enumName = schema.GetEnumName() ?? "enum";
|
||||
OptionSet optionSet = new OptionSet(enumName, schema.Enum.Select(e => new DName((e as OpenApiString).Value)).ToDictionary(k => k, e => e).ToImmutableDictionary());
|
||||
string optionSetName = settings.GetOptionSetName(schema.GetEnumName() ?? openApiParameter.Name);
|
||||
OptionSet optionSet = new OptionSet(optionSetName, schema.Enum.Select(e => new DName((e as OpenApiString).Value)).ToDictionary(k => k, e => e).ToImmutableDictionary());
|
||||
optionSet = settings.OptionSets.TryAddOptionSet(optionSet);
|
||||
return new ConnectorType(schema, openApiParameter, optionSet.FormulaType);
|
||||
}
|
||||
else
|
||||
|
@ -665,6 +722,34 @@ namespace Microsoft.PowerFx.Connectors
|
|||
}
|
||||
}
|
||||
|
||||
// If an OptionSet doesn't exist, we add it (and return it)
|
||||
// If an identical OptionSet exists (same name & list of options), we return it
|
||||
// Otherwise we throw in case of conflict
|
||||
internal static OptionSet TryAddOptionSet(this SymbolTable symbolTable, OptionSet optionSet)
|
||||
{
|
||||
if (optionSet == null)
|
||||
{
|
||||
throw new ArgumentNullException("optionSet");
|
||||
}
|
||||
|
||||
string name = optionSet.EntityName;
|
||||
|
||||
// No existing symbols with that name
|
||||
if (!((INameResolver)symbolTable).Lookup(new DName(name), out NameLookupInfo info, NameLookupPreferences.None))
|
||||
{
|
||||
symbolTable.AddOptionSet(optionSet);
|
||||
return optionSet;
|
||||
}
|
||||
|
||||
// Same optionset already present in table
|
||||
if (info.Kind == BindKind.OptionSet && info.Data is OptionSet existingOptionSet && existingOptionSet.Equals(optionSet))
|
||||
{
|
||||
return existingOptionSet;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Optionset name conflict ({name})");
|
||||
}
|
||||
|
||||
internal static RecordType ToRecordType(this List<(string logicalName, string displayName, FormulaType type)> fields)
|
||||
{
|
||||
if (fields == null)
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
Location = openApiParameter.In;
|
||||
}
|
||||
|
||||
// Intellisense only
|
||||
internal ConnectorParameter(ConnectorParameter connectorParameter, ConnectorType connectorType)
|
||||
: base(connectorParameter, connectorType)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
ConnectorExtensions = new ConnectorExtensions(openApiParameter, bodyExtensions);
|
||||
}
|
||||
|
||||
// Intellisense only
|
||||
internal ConnectorSchema(ConnectorSchema connectorSchema, ConnectorType connectorType)
|
||||
{
|
||||
Schema = connectorSchema.Schema;
|
||||
|
|
|
@ -207,8 +207,9 @@ namespace Microsoft.PowerFx.Connectors
|
|||
{
|
||||
}
|
||||
|
||||
internal ConnectorType(JsonElement schema, ConnectorCompatibility compatibility, IList<SqlRelationship> sqlRelationships, IList<ReferencedEntity> referencedEntities, string datasetName, string name, string connectorName, ICdpTableResolver resolver, ServiceCapabilities serviceCapabilities, bool isTableReadOnly)
|
||||
: this(SwaggerJsonSchema.New(schema), null, new SwaggerParameter(null, true, SwaggerJsonSchema.New(schema), null).GetConnectorType(compatibility, sqlRelationships))
|
||||
// Called by ConnectorFunction.GetCdpTableType
|
||||
internal ConnectorType(JsonElement schema, string tableName, SymbolTable optionSets, ConnectorCompatibility compatibility, IList<SqlRelationship> sqlRelationships, IList<ReferencedEntity> referencedEntities, string datasetName, string name, string connectorName, ICdpTableResolver resolver, ServiceCapabilities serviceCapabilities, bool isTableReadOnly)
|
||||
: this(SwaggerJsonSchema.New(schema), null, new SwaggerParameter(null, true, SwaggerJsonSchema.New(schema), null).GetConnectorType(tableName, optionSets, compatibility, sqlRelationships))
|
||||
{
|
||||
Name = name;
|
||||
|
||||
|
|
|
@ -11,12 +11,16 @@ using System.Threading.Tasks;
|
|||
using Microsoft.PowerFx.Core.Entities;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
#pragma warning disable SA1117
|
||||
|
||||
namespace Microsoft.PowerFx.Connectors
|
||||
{
|
||||
internal class CdpTableResolver : ICdpTableResolver
|
||||
{
|
||||
public ConnectorLogger Logger { get; }
|
||||
|
||||
public IEnumerable<OptionSet> OptionSets { get; private set; }
|
||||
|
||||
private readonly CdpTable _tabularTable;
|
||||
|
||||
private readonly HttpClient _httpClient;
|
||||
|
@ -87,7 +91,12 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
string connectorName = _uriPrefix.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries)[1];
|
||||
|
||||
return ConnectorFunction.GetCdpTableType(this, connectorName, "Schema/Items", FormulaValue.New(text), sqlRelationships, ConnectorCompatibility.CdpCompatibility, _tabularTable.DatasetName, out string name, out string displayName, out TableDelegationInfo delegationInfo);
|
||||
ConnectorType connectorType = ConnectorFunction.GetCdpTableType(this, connectorName, _tabularTable.TableName, "Schema/Items", FormulaValue.New(text), sqlRelationships, ConnectorCompatibility.CdpCompatibility, _tabularTable.DatasetName,
|
||||
out string name, out string displayName, out TableDelegationInfo delegationInfo, out IEnumerable<OptionSet> optionSets);
|
||||
|
||||
OptionSets = optionSets;
|
||||
|
||||
return connectorType;
|
||||
}
|
||||
|
||||
internal static bool IsSql(string uriPrefix) => uriPrefix.Contains("/sql/");
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace Microsoft.PowerFx.Connectors
|
|||
|
||||
public override bool IsDelegable => (DelegationInfo?.SortRestriction != null) || (DelegationInfo?.FilterRestriction != null) || (DelegationInfo?.FilterSupportedFunctions != null);
|
||||
|
||||
public IEnumerable<OptionSet> OptionSets { get; private set; }
|
||||
|
||||
internal TableDelegationInfo DelegationInfo => ((DataSourceInfo)TabularTableDescriptor.FormulaType._type.AssociatedDataSources.First()).DelegationInfo;
|
||||
|
||||
internal override IReadOnlyDictionary<string, Relationship> Relationships => _relationships;
|
||||
|
@ -80,6 +82,7 @@ namespace Microsoft.PowerFx.Connectors
|
|||
TabularTableDescriptor = await tableResolver.ResolveTableAsync(TableName, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_relationships = TabularTableDescriptor.Relationships;
|
||||
OptionSets = tableResolver.OptionSets;
|
||||
|
||||
RecordType = (RecordType)TabularTableDescriptor.FormulaType;
|
||||
}
|
||||
|
@ -88,7 +91,6 @@ namespace Microsoft.PowerFx.Connectors
|
|||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
CdpDataSource cds = new CdpDataSource(DatasetName);
|
||||
DatasetMetadata dm = await CdpDataSource.GetDatasetsMetadataAsync(httpClient, uriPrefix, cancellationToken, logger).ConfigureAwait(false);
|
||||
|
||||
DatasetMetadata = dm ?? throw new InvalidOperationException("Dataset metadata is not available");
|
||||
|
|
|
@ -2557,11 +2557,26 @@ namespace Microsoft.PowerFx.Core.Binding
|
|||
_txb.SetType(node, DType.ObjNull);
|
||||
}
|
||||
|
||||
// Binding TypeLiteralNode from anywhere other than valid type context should be an error.
|
||||
// This ensures that binding of unintended use of TypeLiteralNode eg: "If(Type(Boolean), 1, 2)" will result in an error.
|
||||
// VisitType method is used to resolve the type of TypeLiteralNode from valid context.
|
||||
public override void Visit(TypeLiteralNode node)
|
||||
{
|
||||
AssertValid();
|
||||
Contracts.AssertValue(node);
|
||||
|
||||
_txb.SetType(node, DType.Error);
|
||||
_txb.ErrorContainer.Error(node, TexlStrings.ErrTypeLiteral_UnsupportedUsage);
|
||||
}
|
||||
|
||||
// Method to bind TypeLiteralNode from valid context where a type is expected.
|
||||
// Binding TypeLiteralNode in an expression where a type is not expected invokes the Visit method
|
||||
// from normal visitor pattern and results in error.
|
||||
private void VisitType(TypeLiteralNode node)
|
||||
{
|
||||
AssertValid();
|
||||
Contracts.AssertValue(node);
|
||||
|
||||
if (_nameResolver == null)
|
||||
{
|
||||
_txb.SetType(node, DType.Unknown);
|
||||
|
@ -5103,7 +5118,7 @@ namespace Microsoft.PowerFx.Core.Binding
|
|||
}
|
||||
else if (args[1] is TypeLiteralNode typeLiteral)
|
||||
{
|
||||
typeLiteral.Accept(this);
|
||||
VisitType(typeLiteral);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -131,8 +131,9 @@ namespace Microsoft.PowerFx.Core.Functions
|
|||
/// <param name="bindingConfig">Configuration for an invocation of the binder.</param>
|
||||
/// <param name="features">PowerFx features.</param>
|
||||
/// <param name="rule"></param>
|
||||
/// <param name="updateDisplayNames">If true, the binder will update the display names of the nodes in the parse tree.</param>
|
||||
/// <returns>Returns binding for the function body.</returns>
|
||||
public TexlBinding BindBody(INameResolver nameResolver, IBinderGlue documentBinderGlue, BindingConfig bindingConfig = null, Features features = null, IExternalRule rule = null)
|
||||
public TexlBinding BindBody(INameResolver nameResolver, IBinderGlue documentBinderGlue, BindingConfig bindingConfig = null, Features features = null, IExternalRule rule = null, bool updateDisplayNames = false)
|
||||
{
|
||||
if (nameResolver is null)
|
||||
{
|
||||
|
@ -150,7 +151,7 @@ namespace Microsoft.PowerFx.Core.Functions
|
|||
}
|
||||
|
||||
bindingConfig = bindingConfig ?? new BindingConfig(this._isImperative, userDefinitionsMode: true);
|
||||
_binding = TexlBinding.Run(documentBinderGlue, UdfBody, UserDefinitionsNameResolver.Create(nameResolver, _args, ParamTypes), bindingConfig, features: features, rule: rule);
|
||||
_binding = TexlBinding.Run(documentBinderGlue, UdfBody, UserDefinitionsNameResolver.Create(nameResolver, _args, ParamTypes), bindingConfig, features: features, rule: rule, updateDisplayNames: updateDisplayNames);
|
||||
|
||||
CheckTypesOnDeclaration(_binding.CheckTypesContext, _binding.ResultType, _binding);
|
||||
|
||||
|
@ -199,7 +200,7 @@ namespace Microsoft.PowerFx.Core.Functions
|
|||
/// Clones and binds a user defined function.
|
||||
/// </summary>
|
||||
/// <returns>Returns a new functions.</returns>
|
||||
public UserDefinedFunction WithBinding(INameResolver nameResolver, IBinderGlue binderGlue, out TexlBinding binding, BindingConfig bindingConfig = null, Features features = null, IExternalRule rule = null)
|
||||
public UserDefinedFunction WithBinding(INameResolver nameResolver, IBinderGlue binderGlue, out TexlBinding binding, BindingConfig bindingConfig = null, Features features = null, IExternalRule rule = null, bool updateDisplayNames = false)
|
||||
{
|
||||
if (nameResolver is null)
|
||||
{
|
||||
|
@ -212,7 +213,7 @@ namespace Microsoft.PowerFx.Core.Functions
|
|||
}
|
||||
|
||||
var func = new UserDefinedFunction(Name, ReturnType, UdfBody, _isImperative, new HashSet<UDFArg>(_args), ParamTypes);
|
||||
binding = func.BindBody(nameResolver, binderGlue, bindingConfig, features, rule);
|
||||
binding = func.BindBody(nameResolver, binderGlue, bindingConfig, features, rule, updateDisplayNames);
|
||||
|
||||
return func;
|
||||
}
|
||||
|
|
|
@ -783,6 +783,7 @@ namespace Microsoft.PowerFx.Core.Localization
|
|||
public static ErrorResourceKey WrnUDF_ShadowingBuiltInFunction = new ErrorResourceKey("WrnUDF_ShadowingBuiltInFunction");
|
||||
|
||||
public static ErrorResourceKey ErrTypeLiteral_InvalidTypeDefinition = new ErrorResourceKey("ErrTypeLiteral_InvalidTypeDefinition");
|
||||
public static ErrorResourceKey ErrTypeLiteral_UnsupportedUsage = new ErrorResourceKey("ErrTypeLiteral_UnsupportedUsage");
|
||||
public static ErrorResourceKey ErrNamedType_InvalidCycles = new ErrorResourceKey("ErrNamedType_InvalidCycles");
|
||||
public static ErrorResourceKey ErrNamedType_InvalidTypeDefinition = new ErrorResourceKey("ErrNamedType_InvalidTypeDefinition");
|
||||
public static ErrorResourceKey ErrNamedType_InvalidTypeName = new ErrorResourceKey("ErrNamedType_InvalidTypeName");
|
||||
|
|
|
@ -707,7 +707,7 @@ namespace Microsoft.PowerFx
|
|||
var summary = new CheckContextSummary
|
||||
{
|
||||
AllowsSideEffects = allowSideEffects,
|
||||
IsPreV1Semantics = isV1,
|
||||
IsPreV1Semantics = !isV1,
|
||||
ExpectedReturnType = this._expectedReturnTypes,
|
||||
SuggestedSymbols = symbolEntries
|
||||
};
|
||||
|
|
|
@ -9,18 +9,19 @@ using Microsoft.PowerFx.Core.Utils;
|
|||
|
||||
namespace Microsoft.PowerFx
|
||||
{
|
||||
[ThreadSafeImmutable]
|
||||
public sealed class Features
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable Table syntax to not add "Value:" extra layer.
|
||||
/// </summary>
|
||||
internal bool TableSyntaxDoesntWrapRecords { get; set; }
|
||||
internal bool TableSyntaxDoesntWrapRecords { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable functions to consistently return one dimension tables with
|
||||
/// a "Value" column rather than some other name like "Result".
|
||||
/// </summary>
|
||||
internal bool ConsistentOneColumnTableResult { get; set; }
|
||||
internal bool ConsistentOneColumnTableResult { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Disables support for row-scope disambiguation syntax.
|
||||
|
@ -28,77 +29,72 @@ namespace Microsoft.PowerFx
|
|||
/// instead of
|
||||
/// Filter(A, A[@Value] = 2).
|
||||
/// </summary>
|
||||
internal bool DisableRowScopeDisambiguationSyntax { get; set; }
|
||||
internal bool DisableRowScopeDisambiguationSyntax { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable Identifier support for describing column names.
|
||||
/// </summary>
|
||||
internal bool SupportColumnNamesAsIdentifiers { get; set; }
|
||||
internal bool SupportColumnNamesAsIdentifiers { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Enforces strong-typing for builtin enums, rather than treating
|
||||
/// them as aliases for values of string/number/boolean types.
|
||||
/// </summary>
|
||||
internal bool StronglyTypedBuiltinEnums { get; set; }
|
||||
internal bool StronglyTypedBuiltinEnums { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the IsEmpty function to only allow table arguments, since it
|
||||
/// does not work properly with other types of arguments.
|
||||
/// </summary>
|
||||
internal bool RestrictedIsEmptyArguments { get; set; }
|
||||
internal bool RestrictedIsEmptyArguments { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow delegation for async calls (delegate using awaited call result).
|
||||
/// </summary>
|
||||
internal bool AllowAsyncDelegation { get; set; }
|
||||
internal bool AllowAsyncDelegation { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow delegation for impure nodes.
|
||||
/// </summary>
|
||||
internal bool AllowImpureNodeDelegation { get; set; }
|
||||
internal bool AllowImpureNodeDelegation { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the FirstN/LastN functions to require a second argument, instead of
|
||||
/// defaulting to 1.
|
||||
/// </summary>
|
||||
internal bool FirstLastNRequiresSecondArguments { get; set; }
|
||||
internal bool FirstLastNRequiresSecondArguments { get; init; }
|
||||
|
||||
internal bool PowerFxV1CompatibilityRules { get; set; }
|
||||
internal bool PowerFxV1CompatibilityRules { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// This is required by AsType() in PA delegation analysis.
|
||||
/// </summary>
|
||||
internal bool AsTypeLegacyCheck { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is required by AsType() in Legacy Analysis.
|
||||
/// </summary>
|
||||
internal bool IsLegacyAnalysis { get; set; }
|
||||
internal bool AsTypeLegacyCheck { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Removes support for coercing a control to it's primary output property.
|
||||
/// This only impacts PA Client scenarios, but some code still lives in PFx.
|
||||
/// </summary>
|
||||
internal bool PrimaryOutputPropertyCoercionDeprecated { get; set; }
|
||||
internal bool PrimaryOutputPropertyCoercionDeprecated { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// This is specific for PVA team and it is a temporary feature.
|
||||
/// </summary>
|
||||
internal bool JsonFunctionAcceptsLazyTypes { get; set; }
|
||||
internal bool JsonFunctionAcceptsLazyTypes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables more robust lookup reduction delegation.
|
||||
/// </summary>
|
||||
internal bool IsLookUpReductionDelegationEnabled { get; set; }
|
||||
internal bool IsLookUpReductionDelegationEnabled { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables User-defined types functionality.
|
||||
/// </summary>
|
||||
internal bool IsUserDefinedTypesEnabled { get; set; } = false;
|
||||
internal bool IsUserDefinedTypesEnabled { get; init; } = false;
|
||||
|
||||
internal static Features None => new Features();
|
||||
internal static readonly Features None = new Features();
|
||||
|
||||
public static Features PowerFxV1 => new Features
|
||||
public static readonly Features PowerFxV1 = new Features
|
||||
{
|
||||
TableSyntaxDoesntWrapRecords = true,
|
||||
ConsistentOneColumnTableResult = true,
|
||||
|
@ -130,6 +126,11 @@ namespace Microsoft.PowerFx
|
|||
PowerFxV1CompatibilityRules = other.PowerFxV1CompatibilityRules;
|
||||
PrimaryOutputPropertyCoercionDeprecated = other.PrimaryOutputPropertyCoercionDeprecated;
|
||||
IsUserDefinedTypesEnabled = other.IsUserDefinedTypesEnabled;
|
||||
AllowImpureNodeDelegation = other.AllowImpureNodeDelegation;
|
||||
AllowAsyncDelegation = other.AllowAsyncDelegation;
|
||||
AsTypeLegacyCheck = other.AsTypeLegacyCheck;
|
||||
JsonFunctionAcceptsLazyTypes = other.JsonFunctionAcceptsLazyTypes;
|
||||
IsLookUpReductionDelegationEnabled = other.IsLookUpReductionDelegationEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,11 @@ namespace Microsoft.PowerFx.Syntax
|
|||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Visit(TypeLiteralNode node)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PostVisit(DottedNameNode node)
|
||||
{
|
||||
|
|
|
@ -12,9 +12,7 @@ namespace Microsoft.PowerFx.Syntax
|
|||
/// Visit <see cref="TypeLiteralNode"/> leaf node.
|
||||
/// </summary>
|
||||
/// <param name="node">The visited node.</param>
|
||||
public virtual void Visit(TypeLiteralNode node)
|
||||
{
|
||||
}
|
||||
public abstract void Visit(TypeLiteralNode node);
|
||||
|
||||
/// <summary>
|
||||
/// Visit <see cref="ErrorNode" /> leaf node.
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Microsoft.PowerFx.Core.Texl
|
|||
/// This visitor is used to walkthrough the first node of a filter to get the datasource name and
|
||||
/// whether or not there is any other filter sub expression that uses a view.
|
||||
/// </summary>
|
||||
internal sealed class ViewFilterDataSourceVisitor : TexlVisitor
|
||||
internal sealed class ViewFilterDataSourceVisitor : IdentityTexlVisitor
|
||||
{
|
||||
private const string FilterFunctionName = "Filter";
|
||||
private readonly TexlBinding _txb;
|
||||
|
@ -52,73 +52,5 @@ namespace Microsoft.PowerFx.Core.Texl
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostVisit(DottedNameNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(VariadicOpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(StrInterpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(RecordNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(ListNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(BinaryOpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(UnaryOpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(TableNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(AsNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(ParentNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(NumLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(DecLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(StrLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(BoolLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(BlankNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(ErrorNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(SelfNode node)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Microsoft.PowerFx.Core.Texl
|
|||
/// <summary>
|
||||
/// This visitor is used to walkthrough the tree to check the existence of a view.
|
||||
/// </summary>
|
||||
internal sealed class ViewFinderVisitor : TexlVisitor
|
||||
internal sealed class ViewFinderVisitor : IdentityTexlVisitor
|
||||
{
|
||||
private readonly TexlBinding _txb;
|
||||
|
||||
|
@ -42,73 +42,5 @@ namespace Microsoft.PowerFx.Core.Texl
|
|||
ContainsView = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void PostVisit(CallNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(VariadicOpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(StrInterpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(RecordNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(ListNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(BinaryOpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(UnaryOpNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(TableNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void PostVisit(AsNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(ParentNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(NumLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(DecLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(StrLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(BoolLitNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(BlankNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(ErrorNode node)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Visit(SelfNode node)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PowerFx.Core.IR;
|
||||
using Microsoft.PowerFx.Core.Utils;
|
||||
|
@ -697,29 +698,50 @@ namespace Microsoft.PowerFx.Functions
|
|||
}
|
||||
}
|
||||
|
||||
private static readonly Regex TimeValueRegex = new Regex(@"(?<hours>\d{1,2})\:(?<minutes>\d{2})(\:(?<seconds>\d{2})(\.(?<milliseconds>\d{1,3}))?)?");
|
||||
|
||||
public static FormulaValue TimeParse(EvalVisitor runner, EvalVisitorContext context, IRContext irContext, StringValue[] args)
|
||||
{
|
||||
var str = args[0].Value;
|
||||
var dateTimeResult = DateTimeParse(runner, context, IRContext.NotInSource(FormulaType.DateTime), args);
|
||||
if (dateTimeResult is DateTimeValue dateTimeValue)
|
||||
{
|
||||
var dt = dateTimeValue.GetConvertedValue(runner.TimeZoneInfo);
|
||||
var time = new TimeSpan(0, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
|
||||
return new TimeValue(irContext, time);
|
||||
}
|
||||
|
||||
// culture will have Cultural info in-case one was passed in argument else it will have the default one.
|
||||
CultureInfo culture = runner.CultureInfo;
|
||||
if (args.Length > 1)
|
||||
if (dateTimeResult is BlankValue)
|
||||
{
|
||||
var languageCode = args[1].Value;
|
||||
if (!TextFormatUtils.TryGetCulture(languageCode, out culture))
|
||||
return dateTimeResult;
|
||||
}
|
||||
|
||||
// Error; trying time-only options
|
||||
var match = TimeValueRegex.Match(args[0].Value);
|
||||
if (match.Success)
|
||||
{
|
||||
return CommonErrors.BadLanguageCode(irContext, languageCode);
|
||||
var hours = int.Parse(match.Groups["hours"].Value, CultureInfo.InvariantCulture) % 24;
|
||||
var minutes = int.Parse(match.Groups["minutes"].Value, CultureInfo.InvariantCulture);
|
||||
var secondsText = match.Groups["seconds"]?.Value;
|
||||
var seconds = string.IsNullOrEmpty(secondsText) ? 0 : int.Parse(secondsText, CultureInfo.InvariantCulture);
|
||||
var millisecondsText = match.Groups["milliseconds"]?.Value;
|
||||
int milliseconds = 0;
|
||||
if (!string.IsNullOrEmpty(millisecondsText))
|
||||
{
|
||||
milliseconds = int.Parse(millisecondsText, CultureInfo.InvariantCulture);
|
||||
if (millisecondsText.Length == 1)
|
||||
{
|
||||
milliseconds *= 100; // 12:34:56.7 === 12:34:56.700
|
||||
}
|
||||
else if (millisecondsText.Length == 2)
|
||||
{
|
||||
milliseconds *= 10; // 12:34:56.78 === 12:34:56.780
|
||||
}
|
||||
}
|
||||
|
||||
if (TimeSpan.TryParse(str, runner.CultureInfo, out var result))
|
||||
{
|
||||
return new TimeValue(irContext, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CommonErrors.InvalidDateTimeParsingError(irContext);
|
||||
return new TimeValue(irContext, new TimeSpan(0, hours, minutes, seconds, milliseconds));
|
||||
}
|
||||
|
||||
return dateTimeResult;
|
||||
}
|
||||
|
||||
// Returns the number of minutes between UTC and either local or defined time zone
|
||||
|
|
|
@ -4560,6 +4560,10 @@
|
|||
<value>Type literal declaration is invalid. The expression '{0}' cannot be used in a type definition.</value>
|
||||
<comment>Error message when validation of type literal fails.</comment>
|
||||
</data>
|
||||
<data name="ErrTypeLiteral_UnsupportedUsage" xml:space="preserve">
|
||||
<value>Unsupported usage: type literals can only be used in type arguments and type definitions.</value>
|
||||
<comment>Error message shown when a type literal is used in an unsupported expression.</comment>
|
||||
</data>
|
||||
<data name="ErrNamedType_InvalidTypeDefinition" xml:space="preserve">
|
||||
<value>Definition of type {0} is invalid.</value>
|
||||
<comment>Error message when type binding is invalid.</comment>
|
||||
|
|
|
@ -33,9 +33,9 @@ namespace Microsoft.PowerFx.Tests
|
|||
|
||||
string text = (string)LoggingTestServer.GetFileText(@"Responses\Compatibility GetSchema.json");
|
||||
|
||||
ConnectorType ctCdp = ConnectorFunction.GetCdpTableType(tableResolver, "name", "schema/items", StringValue.New(text), null, ConnectorCompatibility.CdpCompatibility, "dataset", out _, out _, out _);
|
||||
ConnectorType ctPa = ConnectorFunction.GetCdpTableType(tableResolver, "name", "schema/items", StringValue.New(text), null, ConnectorCompatibility.PowerAppsCompatibility, "dataset", out _, out _, out _);
|
||||
ConnectorType ctSw = ConnectorFunction.GetCdpTableType(tableResolver, "name", "schema/items", StringValue.New(text), null, ConnectorCompatibility.SwaggerCompatibility, "dataset", out _, out _, out _);
|
||||
ConnectorType ctCdp = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), null, ConnectorCompatibility.CdpCompatibility, "dataset", out _, out _, out _, out _);
|
||||
ConnectorType ctPa = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), null, ConnectorCompatibility.PowerAppsCompatibility, "dataset", out _, out _, out _, out _);
|
||||
ConnectorType ctSw = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), null, ConnectorCompatibility.SwaggerCompatibility, "dataset", out _, out _, out _, out _);
|
||||
|
||||
string cdp = ctCdp.FormulaType.ToStringWithDisplayNames();
|
||||
string pa = ctPa.FormulaType.ToStringWithDisplayNames();
|
||||
|
|
|
@ -1373,7 +1373,8 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
public static string GetString(this OpenApiSchema schema)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
schema.GetStringInternal(new ConnectorTypeGetterSettings(0), sb);
|
||||
SymbolTable optionSets = new SymbolTable();
|
||||
schema.GetStringInternal(new ConnectorTypeGetterSettings(0, null, optionSets), sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)SafeDTypeToStringTests.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Shims462.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)SwaggerFailureTests.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)SymbolTableTryAddTests.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TestConnectorRuntimeContext.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ThreadingTests.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Helpers\Helpers.cs" />
|
||||
|
|
|
@ -962,8 +962,8 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
|
||||
Assert.Equal(
|
||||
"r![assignee_id:w, brand_id:w, collaborator_ids:s, created_at:d, custom_fields:s, description:s, due_at:d, external_id:s, followup_ids:s, forum_topic_id:w, group_id:w, has_incidents:b, " +
|
||||
"id:w, organization_id:w, priority:l, problem_id:w, raw_subject:s, recipient:s, requester_id:w, satisfaction_rating:s, sharing_agreement_ids:s, status:s, subject:s, submitter_id:w, " +
|
||||
"tags:s, ticket_form_id:w, type:s, updated_at:d, url:s, via:s]", ((CdpRecordType)zdTable.RecordType).ToStringWithDisplayNames());
|
||||
"id:w, organization_id:w, priority:l, problem_id:w, raw_subject:s, recipient:s, requester_id:w, satisfaction_rating:s, sharing_agreement_ids:s, status:l, subject:s, submitter_id:w, " +
|
||||
"tags:s, ticket_form_id:w, type:l, updated_at:d, url:s, via:s]", ((CdpRecordType)zdTable.RecordType).ToStringWithDisplayNames());
|
||||
|
||||
SymbolValues symbolValues = new SymbolValues().Add("Tickets", zdTable);
|
||||
RuntimeConfig rc = new RuntimeConfig(symbolValues).AddService<ConnectorLogger>(logger);
|
||||
|
@ -979,7 +979,10 @@ namespace Microsoft.PowerFx.Connectors.Tests
|
|||
|
||||
OptionSetValue priority = Assert.IsType<OptionSetValue>(result);
|
||||
Assert.Equal("normal", priority.Option);
|
||||
Assert.Equal("normal", priority.DisplayName);
|
||||
Assert.Equal("Normal", priority.DisplayName);
|
||||
|
||||
Assert.NotNull(connectorTable.OptionSets);
|
||||
Assert.Equal("priority (tickets), status (tickets), type (tickets)", string.Join(", ", connectorTable.OptionSets.Select(os => os.EntityName.Value).OrderBy(x => x)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,254 +18,308 @@
|
|||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"title": "id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-keyOrder": 1,
|
||||
"x-ms-keyType": "primary",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "url",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"external_id": {
|
||||
"type": "string",
|
||||
"title": "external_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"x-ms-enum-values": [
|
||||
{
|
||||
"value": "problem",
|
||||
"displayName": "Problem"
|
||||
},
|
||||
{
|
||||
"value": "incident",
|
||||
"displayName": "Incident"
|
||||
},
|
||||
{
|
||||
"value": "question",
|
||||
"displayName": "Question"
|
||||
},
|
||||
{
|
||||
"value": "task",
|
||||
"displayName": "Task"
|
||||
}
|
||||
],
|
||||
"title": "type",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"subject": {
|
||||
"type": "string",
|
||||
"title": "subject",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"raw_subject": {
|
||||
"type": "string",
|
||||
"title": "raw_subject",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"title": "description",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"x-ms-enum-values": [
|
||||
{
|
||||
"value": "low",
|
||||
"displayName": "Low"
|
||||
},
|
||||
{
|
||||
"value": "normal",
|
||||
"displayName": "Normal"
|
||||
},
|
||||
{
|
||||
"value": "high",
|
||||
"displayName": "High"
|
||||
},
|
||||
{
|
||||
"value": "urgent",
|
||||
"displayName": "Urgent"
|
||||
}
|
||||
],
|
||||
"title": "priority",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"normal",
|
||||
"high",
|
||||
"urgent"
|
||||
],
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"x-ms-enum-values": [
|
||||
{
|
||||
"value": "new",
|
||||
"displayName": "New"
|
||||
},
|
||||
{
|
||||
"value": "open",
|
||||
"displayName": "Open"
|
||||
},
|
||||
{
|
||||
"value": "pending",
|
||||
"displayName": "Pending"
|
||||
},
|
||||
{
|
||||
"value": "hold",
|
||||
"displayName": "Hold"
|
||||
},
|
||||
{
|
||||
"value": "solved",
|
||||
"displayName": "Solved"
|
||||
},
|
||||
{
|
||||
"value": "closed",
|
||||
"displayName": "Closed"
|
||||
}
|
||||
],
|
||||
"title": "status",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"recipient": {
|
||||
"type": "string",
|
||||
"title": "recipient",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "contains", "startswith", "endswith", "length", "indexof", "replace", "substring", "substringof", "tolower", "toupper", "trim", "concat" ] },
|
||||
"type": "string",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"requester_id": {
|
||||
"type": "integer",
|
||||
"title": "requester_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"submitter_id": {
|
||||
"type": "integer",
|
||||
"title": "submitter_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"assignee_id": {
|
||||
"type": "integer",
|
||||
"title": "assignee_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"organization_id": {
|
||||
"type": "integer",
|
||||
"title": "organization_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"group_id": {
|
||||
"type": "integer",
|
||||
"title": "group_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"collaborator_ids": {
|
||||
"title": "collaborator_ids",
|
||||
"type": "string",
|
||||
"title": "collaborator_ids",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"forum_topic_id": {
|
||||
"type": "integer",
|
||||
"title": "forum_topic_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"problem_id": {
|
||||
"type": "integer",
|
||||
"title": "problem_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"has_incidents": {
|
||||
"type": "boolean",
|
||||
"title": "has_incidents",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "not", "and", "or" ] },
|
||||
"type": "boolean",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"due_at": {
|
||||
"type": "string",
|
||||
"title": "due_at",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time", "totaloffsetminutes" ] },
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"tags": {
|
||||
"title": "tags",
|
||||
"type": "string",
|
||||
"title": "tags",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"via": {
|
||||
"title": "via",
|
||||
"type": "string",
|
||||
"title": "via",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"custom_fields": {
|
||||
"title": "custom_fields",
|
||||
"type": "string",
|
||||
"title": "custom_fields",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"satisfaction_rating": {
|
||||
"title": "satisfaction_rating",
|
||||
"type": "string",
|
||||
"title": "satisfaction_rating",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"sharing_agreement_ids": {
|
||||
"title": "sharing_agreement_ids",
|
||||
"type": "string",
|
||||
"title": "sharing_agreement_ids",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"followup_ids": {
|
||||
"title": "followup_ids",
|
||||
"type": "string",
|
||||
"title": "followup_ids",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"ticket_form_id": {
|
||||
"type": "integer",
|
||||
"title": "ticket_form_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"brand_id": {
|
||||
"type": "integer",
|
||||
"title": "brand_id",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "add", "sub", "mul", "div", "mod", "negate", "sum", "average" ] },
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": -9223372036854775808,
|
||||
"maximum": 9223372036854775807,
|
||||
"minimum": -9223372036854776000,
|
||||
"maximum": 9223372036854776000,
|
||||
"x-ms-permission": "read-write",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"title": "created_at",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time", "totaloffsetminutes" ] },
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string",
|
||||
"title": "updated_at",
|
||||
"x-ms-capabilities": { "filterFunctions": [ "lt", "le", "eq", "ne", "gt", "ge", "min", "max", "countdistinct", "day", "month", "year", "hour", "minute", "second", "date", "time", "totaloffsetminutes" ] },
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"x-ms-permission": "read-only",
|
||||
"x-ms-sort": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-ms-permission": "read-write"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.PowerFx.Core;
|
||||
using Microsoft.PowerFx.Core.Utils;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.PowerFx.Connectors.Tests.Shared
|
||||
{
|
||||
public class SymbolTableTryAddOptionSetTests
|
||||
{
|
||||
[Fact]
|
||||
public void TryAddOptionSet()
|
||||
{
|
||||
SymbolTable symbolTable = new SymbolTable();
|
||||
|
||||
SingleSourceDisplayNameProvider dnp = new SingleSourceDisplayNameProvider();
|
||||
dnp = dnp.AddField(new DName("logical1"), new DName("display1"));
|
||||
dnp = dnp.AddField(new DName("logical2"), new DName("display2"));
|
||||
|
||||
OptionSet os1 = new OptionSet("os1", dnp);
|
||||
OptionSet os2 = new OptionSet("os1", dnp);
|
||||
|
||||
OptionSet os = symbolTable.TryAddOptionSet(os1);
|
||||
Assert.Same(os1, os);
|
||||
|
||||
// twice the same, nothing added
|
||||
os = symbolTable.TryAddOptionSet(os1);
|
||||
Assert.Same(os1, os);
|
||||
Assert.Single(symbolTable.OptionSets);
|
||||
|
||||
// still the same, nothing added
|
||||
os = symbolTable.TryAddOptionSet(os2);
|
||||
Assert.Same(os1, os);
|
||||
Assert.Single(symbolTable.OptionSets);
|
||||
|
||||
dnp = dnp.AddField(new DName("logical3"), new DName("display3"));
|
||||
OptionSet os3 = new OptionSet("os3", dnp);
|
||||
|
||||
// new optionSet
|
||||
os = symbolTable.TryAddOptionSet(os3);
|
||||
Assert.NotSame(os, os1);
|
||||
Assert.Equal(2, symbolTable.OptionSets.Count());
|
||||
|
||||
// try a name conflict now
|
||||
OptionSet os4 = new OptionSet("os1", dnp);
|
||||
|
||||
InvalidOperationException ioe = Assert.Throws<InvalidOperationException>(() => symbolTable.TryAddOptionSet(os4));
|
||||
Assert.Equal("Optionset name conflict (os1)", ioe.Message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -138,6 +138,11 @@ namespace Microsoft.PowerFx.Core.Tests
|
|||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Visit(TypeLiteralNode node)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,3 +234,7 @@ Error({Kind:ErrorKind.InvalidArgument})
|
|||
// Numeric enums and numbers
|
||||
>> If(1<0, 1, ErrorKind.Validation)
|
||||
11
|
||||
|
||||
// Type literal should cause error
|
||||
>> If(Type(Boolean), 1, 2)
|
||||
Errors: Error 7-8: Unsupported usage: type literals can only be used in type arguments and type definitions.|Error 0-2: The function 'If' has some invalid arguments.
|
|
@ -0,0 +1,56 @@
|
|||
>> TimeValue("12:00:00")
|
||||
Time(12,0,0,0)
|
||||
|
||||
>> TimeValue("27:00:00")
|
||||
Time(3,0,0,0)
|
||||
|
||||
// TimeValue only returns values between [00:00:00.000, 23:59:59.999)
|
||||
>> Value(TimeValue("27:00:00"))
|
||||
0.125
|
||||
|
||||
>> TimeValue("6:00")
|
||||
Time(6,0,0,0)
|
||||
|
||||
>> TimeValue("6:00 PM")
|
||||
Time(18,0,0,0)
|
||||
|
||||
// Date portion is ignored
|
||||
>> Value(TimeValue("10/12/2024 6:00:00 AM"))
|
||||
0.25
|
||||
|
||||
>> TimeValue("29 Feb 2008 9:21:33 AM")
|
||||
Time(9,21,33,0)
|
||||
|
||||
>> TimeValue("12:34:56.7")
|
||||
Time(12,34,56,700)
|
||||
|
||||
>> TimeValue("12:34:56.78")
|
||||
Time(12,34,56,780)
|
||||
|
||||
>> TimeValue("12:34:56.789")
|
||||
Time(12,34,56,789)
|
||||
|
||||
// Extra digits on milliseconds are truncated
|
||||
>> TimeValue("11:22:33.4449999")
|
||||
Time(11,22,33,444)
|
||||
|
||||
>> TimeValue("6:01:02")
|
||||
Time(6,1,2,0)
|
||||
|
||||
>> TimeValue("14:18")
|
||||
Time(14,18,0,0)
|
||||
|
||||
>> TimeValue("24:11:11")
|
||||
Time(0,11,11,0)
|
||||
|
||||
>> TimeValue("Not a time")
|
||||
Error({Kind:ErrorKind.InvalidArgument})
|
||||
|
||||
>> TimeValue("One PM")
|
||||
Error({Kind:ErrorKind.InvalidArgument})
|
||||
|
||||
>> TimeValue("1234")
|
||||
Error({Kind:ErrorKind.InvalidArgument})
|
||||
|
||||
>> TimeValue("20241106073000")
|
||||
Error({Kind:ErrorKind.InvalidArgument})
|
|
@ -147,3 +147,6 @@ Errors: Error 16-23: Invalid argument 'Blank()'. Expected valid type name or typ
|
|||
|
||||
>> ParseJSON("42", 1/0)
|
||||
Errors: Error 17-18: Invalid argument '1 / 0'. Expected valid type name or type literal.
|
||||
|
||||
>> ParseJSON(Type(Text))
|
||||
Errors: Error 14-15: Unsupported usage: type literals can only be used in type arguments and type definitions.|Error 0-9: The function 'ParseJSON' has some invalid arguments.
|
|
@ -278,11 +278,11 @@ Date(2000,1,10)
|
|||
Time(0,0,0,0)
|
||||
|
||||
//Time-String
|
||||
>> Switch("Case1","Case2",Time(6,30,30),"Case1","1")
|
||||
Time(0,0,0,0)
|
||||
>> Switch("Case1","Case2",Time(6,30,30),"Case1","12:34:56")
|
||||
Time(12,34,56,0)
|
||||
|
||||
>> Switch("Case1","Case2",Time(6,30,30),"Case1","200")
|
||||
Time(0,0,0,0)
|
||||
>> Switch("Case1","Case2",Time(6,30,30),"Case1","6:00")
|
||||
Time(6,0,0,0)
|
||||
|
||||
>> Switch("Case1","Case2",Time(6,30,30),"Case1","AB$%^")
|
||||
Error({Kind:ErrorKind.InvalidArgument})
|
||||
|
|
|
@ -4411,6 +4411,19 @@ namespace Microsoft.PowerFx.Core.Tests
|
|||
features: Features.PowerFxV1);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Type(Number)", "e")]
|
||||
[InlineData("Abs(Type(Number))", "n")]
|
||||
[InlineData("If(Type(Boolean), 1, 2)", "n")]
|
||||
[InlineData("Concatenate(Type(Text))", "s")]
|
||||
public void TestTypeLiteralsNegative(string script, string expectedSchema)
|
||||
{
|
||||
TestBindingErrors(
|
||||
script,
|
||||
TestUtils.DT(expectedSchema),
|
||||
features: Features.PowerFxV1);
|
||||
}
|
||||
|
||||
private void TestBindingPurity(string script, bool isPure, SymbolTable symbolTable = null)
|
||||
{
|
||||
var config = new PowerFxConfig
|
||||
|
|
|
@ -23,9 +23,12 @@ namespace Microsoft.PowerFx.Json.Tests
|
|||
{
|
||||
private RecalcEngine SetupEngine(bool udtFeaturedEnabled = true)
|
||||
{
|
||||
var config = new PowerFxConfig();
|
||||
var features = new Features(Features.PowerFxV1)
|
||||
{
|
||||
IsUserDefinedTypesEnabled = udtFeaturedEnabled,
|
||||
};
|
||||
var config = new PowerFxConfig(features);
|
||||
config.EnableJsonFunctions();
|
||||
config.Features.IsUserDefinedTypesEnabled = udtFeaturedEnabled;
|
||||
return new RecalcEngine(config);
|
||||
}
|
||||
|
||||
|
@ -118,31 +121,34 @@ namespace Microsoft.PowerFx.Json.Tests
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("\"42\"", "SomeType", true, "ErrInvalidName")]
|
||||
[InlineData("\"42\"", "Type(5)", true, "ErrTypeLiteral_InvalidTypeDefinition")]
|
||||
[InlineData("\"42\"", "Text(42)", true, "ErrInvalidArgumentExpectedType")]
|
||||
[InlineData("\"\"\"Hello\"\"\"", "\"Hello\"", true, "ErrInvalidArgumentExpectedType")]
|
||||
[InlineData("\"{}\"", "Type([{a: 42}])", true, "ErrTypeLiteral_InvalidTypeDefinition")]
|
||||
[InlineData("AsType(ParseJSON(\"42\"))", "", false, "ErrBadArity")]
|
||||
[InlineData("IsType(ParseJSON(\"42\"))", "", false, "ErrBadArity")]
|
||||
[InlineData("AsType(ParseJSON(\"42\"), Number , Text(5))", "", false, "ErrBadArity")]
|
||||
[InlineData("IsType(ParseJSON(\"42\"), Number, 5)", "", false, "ErrBadArity")]
|
||||
[InlineData("AsType(ParseJSON(\"123\"), 1)", "", false, "ErrInvalidArgumentExpectedType")]
|
||||
public void TestCompileErrors(string expression, string type, bool testAllFunctions, string expectedError)
|
||||
[InlineData("\"42\"", "SomeType", "ErrInvalidName")]
|
||||
[InlineData("\"42\"", "Type(5)", "ErrTypeLiteral_InvalidTypeDefinition")]
|
||||
[InlineData("\"42\"", "Text(42)", "ErrInvalidArgumentExpectedType")]
|
||||
[InlineData("\"\"\"Hello\"\"\"", "\"Hello\"", "ErrInvalidArgumentExpectedType")]
|
||||
[InlineData("\"{}\"", "Type([{a: 42}])", "ErrTypeLiteral_InvalidTypeDefinition")]
|
||||
public void TestCompileErrorsAllStronglyTypedOverloads(string expression, string type, string expectedError)
|
||||
{
|
||||
var engine = SetupEngine();
|
||||
CheckIsTypeAsTypeParseJSONCompileErrors(engine, expression, type, expectedError);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AsType(ParseJSON(\"42\"))", "ErrBadArity")]
|
||||
[InlineData("IsType(ParseJSON(\"42\"))", "ErrBadArity")]
|
||||
[InlineData("AsType(ParseJSON(\"42\"), Number , Text(5))", "ErrBadArity")]
|
||||
[InlineData("IsType(ParseJSON(\"42\"), Number, 5)", "ErrBadArity")]
|
||||
[InlineData("AsType(ParseJSON(\"123\"), 1)", "ErrInvalidArgumentExpectedType")]
|
||||
[InlineData("AsType(Type(UntypedObject), ParseJSON(\"123\"))", "ErrTypeLiteral_UnsupportedUsage")]
|
||||
[InlineData("IsType(Type(UntypedObject), Type(Boolean))", "ErrTypeLiteral_UnsupportedUsage")]
|
||||
[InlineData("ParseJSON(Type(Text), Type(Text))", "ErrTypeLiteral_UnsupportedUsage")]
|
||||
public void TestCompileErrors(string expression, string expectedError)
|
||||
{
|
||||
var engine = SetupEngine();
|
||||
|
||||
if (testAllFunctions)
|
||||
{
|
||||
CheckIsTypeAsTypeParseJSONCompileErrors(engine, expression, type, expectedError);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = engine.Check(expression);
|
||||
Assert.False(result.IsSuccess);
|
||||
Assert.Contains(result.Errors, e => e.MessageKey == expectedError);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("AsType(ParseJSON(\"123\"), Number)")]
|
||||
|
|
Загрузка…
Ссылка в новой задаче