Skip to content

Commit

Permalink
JSON function: serialize UO (#2639)
Browse files Browse the repository at this point in the history
>> JSON(ParseJSON("{""a"": 1}"), JSONFormat.IgnoreUnsupportedTypes)
"{""a"":1}"
  • Loading branch information
LucGenetier authored Sep 25, 2024
1 parent 93daa65 commit ee0ca2c
Show file tree
Hide file tree
Showing 11 changed files with 510 additions and 35 deletions.
2 changes: 2 additions & 0 deletions src/libraries/Microsoft.PowerFx.Core/Localization/Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -845,5 +845,7 @@ internal static class TexlStrings
public static ErrorResourceKey ErrInvalidDataSourceForFunction = new ErrorResourceKey("ErrInvalidDataSourceForFunction");
public static ErrorResourceKey ErrInvalidArgumentExpectedType = new ErrorResourceKey("ErrInvalidArgumentExpectedType");
public static ErrorResourceKey ErrUnsupportedTypeInTypeArgument = new ErrorResourceKey("ErrUnsupportedTypeInTypeArgument");
public static ErrorResourceKey ErrReachedMaxJsonDepth = new ErrorResourceKey("ErrReachedMaxJsonDepth");
public static ErrorResourceKey ErrReachedMaxJsonLength = new ErrorResourceKey("ErrReachedMaxJsonLength");
}
}
46 changes: 46 additions & 0 deletions src/libraries/Microsoft.PowerFx.Core/Public/Canceller.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;

namespace Microsoft.PowerFx
{
internal class Canceller
{
private readonly List<Action> _cancellationAction;

public Canceller()
{
_cancellationAction = new List<Action>();
}

public Canceller(params Action[] cancellationActions)
: this()
{
if (cancellationActions != null)
{
foreach (Action cancellationAction in cancellationActions)
{
AddAction(cancellationAction);
}
}
}

public void AddAction(Action cancellationAction)
{
if (cancellationAction != null)
{
_cancellationAction.Add(cancellationAction);
}
}

public void ThrowIfCancellationRequested()
{
foreach (Action cancellationAction in _cancellationAction)
{
cancellationAction();
}
}
}
}
25 changes: 12 additions & 13 deletions src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Json.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.PowerFx.Core.Texl.Builtins
{
// JSON(data:any, [format:s])
internal class JsonFunction : BuiltinFunction
{
{
private const char _includeBinaryDataEnumValue = 'B';
private const char _ignoreBinaryDataEnumValue = 'G';
private const char _ignoreUnsupportedTypesEnumValue = 'I';
Expand All @@ -31,26 +31,25 @@ internal class JsonFunction : BuiltinFunction
DKind.DataEntity,
DKind.LazyRecord,
DKind.LazyTable,
DKind.View,
DKind.View,
DKind.ViewValue
};

private static readonly DKind[] _unsupportedTypes = new[]
{
DKind.Control,
DKind.Control,
DKind.LazyRecord,
DKind.LazyTable,
DKind.Metadata,
DKind.OptionSet,
DKind.PenImage,
DKind.OptionSet,
DKind.PenImage,
DKind.Polymorphic,
DKind.UntypedObject,
DKind.Void
};

public override bool IsSelfContained => true;

public override bool IsAsync => true;
public override bool IsAsync => true;

public override bool SupportsParamCoercion => false;

Expand Down Expand Up @@ -78,13 +77,13 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
// Do not call base.CheckTypes for arg0
if (args.Length > 1)
{
if (context.Features.StronglyTypedBuiltinEnums &&
if (context.Features.StronglyTypedBuiltinEnums &&
!base.CheckType(context, args[1], argTypes[1], BuiltInEnums.JSONFormatEnum.FormulaType._type, errors, ref nodeToCoercedTypeMap))
{
return false;
}

TexlNode optionsNode = args[1];
TexlNode optionsNode = args[1];
if (!IsConstant(context, argTypes, optionsNode, out string nodeValue))
{
errors.EnsureError(optionsNode, TexlStrings.ErrFunctionArg2ParamMustBeConstant, "JSON", TexlStrings.JSONArg2.Invoke());
Expand Down Expand Up @@ -117,11 +116,11 @@ public override void CheckSemantics(TexlBinding binding, TexlNode[] args, DType[

bool includeBinaryData = false;
bool ignoreUnsupportedTypes = false;
bool ignoreBinaryData = false;
bool ignoreBinaryData = false;

if (args.Length > 1)
{
TexlNode optionsNode = args[1];
TexlNode optionsNode = args[1];
if (!IsConstant(binding.CheckTypesContext, argTypes, optionsNode, out string nodeValue))
{
return;
Expand Down Expand Up @@ -180,12 +179,12 @@ public override void CheckSemantics(TexlBinding binding, TexlNode[] args, DType[
}

if (!ignoreUnsupportedTypes)
{
{
if (HasUnsupportedType(dataArgType, supportsLazyTypes, out DType unsupportedNestedType, out var unsupportedColumnName))
{
errors.EnsureError(dataNode, TexlStrings.ErrJSONArg1UnsupportedNestedType, unsupportedColumnName, unsupportedNestedType.GetKindString());
}
}
}
}

private static bool IsConstant(CheckTypesContext context, DType[] argTypes, TexlNode optionsNode, out string nodeValue)
Expand Down
14 changes: 13 additions & 1 deletion src/libraries/Microsoft.PowerFx.Interpreter/EvalVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,19 @@ public override async ValueTask<FormulaValue> Visit(CallNode node, EvalVisitorCo
}
else if (func is IAsyncTexlFunction5 asyncFunc5)
{
result = await asyncFunc5.InvokeAsync(_services, node.IRContext.ResultType, args, _cancellationToken).ConfigureAwait(false);
BasicServiceProvider services2 = new BasicServiceProvider(_services);

if (services2.GetService(typeof(TimeZoneInfo)) == null)
{
services2.AddService(TimeZoneInfo);
}

if (services2.GetService(typeof(Canceller)) == null)
{
services2.AddService(new Canceller(CheckCancel));
}

result = await asyncFunc5.InvokeAsync(services2, node.IRContext.ResultType, args, _cancellationToken).ConfigureAwait(false);
}
else if (func is IAsyncConnectorTexlFunction asyncConnectorTexlFunction)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
using System.Threading.Tasks;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.IR;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;
using Microsoft.PowerFx.Functions;
using Microsoft.PowerFx.Types;

namespace Microsoft.PowerFx.Core.Texl.Builtins
Expand All @@ -18,6 +16,7 @@ internal class AsTypeFunction_UOImpl : AsTypeFunction_UO, IAsyncTexlFunction4
public async Task<FormulaValue> InvokeAsync(TimeZoneInfo timezoneInfo, FormulaType ft, FormulaValue[] args, CancellationToken cancellationToken)
{
Contracts.Assert(args.Length == 2);
cancellationToken.ThrowIfCancellationRequested();

var irContext = IRContext.NotInSource(ft);
var typeString = (StringValue)args[1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
using System.Threading.Tasks;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.IR;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;
using Microsoft.PowerFx.Functions;
using Microsoft.PowerFx.Types;

namespace Microsoft.PowerFx.Core.Texl.Builtins
Expand All @@ -18,6 +16,7 @@ internal class IsTypeFunction_UOImpl : IsTypeFunction_UO, IAsyncTexlFunction4
public async Task<FormulaValue> InvokeAsync(TimeZoneInfo timezoneInfo, FormulaType ft, FormulaValue[] args, CancellationToken cancellationToken)
{
Contracts.Assert(args.Length == 2);
cancellationToken.ThrowIfCancellationRequested();

var irContext = IRContext.NotInSource(FormulaType.UntypedObject);
var typeString = (StringValue)args[1];
Expand Down
Loading

0 comments on commit ee0ca2c

Please sign in to comment.