Codeunit 9044 ABS Format Helper, source in 24

Source242526272829metadata in 24

src/System Application/App/Azure Blob Services API/src/Helper/ABSFormatHelper.Codeunit.al289 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------

namespace System.Azure.Storage;

using System;
using System.Utilities;
using System.Text;

codeunit 9044 "ABS Format Helper"
{
    Access = Internal;
    InherentEntitlements = X;
    InherentPermissions = X;

    [NonDebuggable]
    procedure AppendToUri(var UriText: Text; ParameterIdentifier: Text; ParameterValue: Text)
    var
        Uri: Codeunit Uri;
        ConcatChar: Text;
        AppendType1Lbl: Label '%1%2=%3', Comment = '%1 = Concatenation character, %2 = Parameter Identifer, %3 = Parameter Value', Locked = true;
        AppendType2Lbl: Label '%1%2', Comment = '%1 = Concatenation character, %2 = Parameter Value', Locked = true;
        EscapedParameterValue: Text;
    begin
        ConcatChar := '?';
        if UriText.Contains('?') then
            ConcatChar := '&';
        EscapedParameterValue := Uri.EscapeDataString(ParameterValue);
        if ParameterIdentifier <> '' then
            UriText += StrSubstNo(AppendType1Lbl, ConcatChar, ParameterIdentifier, EscapedParameterValue)
        else
            UriText += StrSubstNo(AppendType2Lbl, ConcatChar, EscapedParameterValue)
    end;

    [NonDebuggable]
    procedure RemoveCurlyBracketsFromString("Value": Text): Text
    begin
        exit(DelChr("Value", '=', '{}'));
    end;

    [NonDebuggable]
    procedure GetBase64BlockId(): Text
    begin
        exit(GetBase64BlockId(RemoveCurlyBracketsFromString(Format(CreateGuid()))));
    end;

    [NonDebuggable]
    procedure GetBase64BlockId(BlockId: Text): Text
    var
        Base64Convert: Codeunit "Base64 Convert";
        Uri: Codeunit Uri;
    begin
        exit(Uri.EscapeDataString(Base64Convert.ToBase64(BlockId)));
    end;

    [NonDebuggable]
    procedure BlockDictionariesToBlockListDictionary(CommitedBlocks: Dictionary of [Text, Integer]; UncommitedBlocks: Dictionary of [Text, Integer]; var BlockList: Dictionary of [Text, Text]; OverwriteValueToLatest: Boolean)
    var
        Keys: List of [Text];
        "Key": Text;
        "Value": Text;
    begin
        "Value" := 'Committed';
        if OverwriteValueToLatest then
            "Value" := 'Latest';
        Keys := CommitedBlocks.Keys;
        foreach "Key" in Keys do
            BlockList.Add("Key", "Value");

        "Value" := 'Uncommitted';
        if OverwriteValueToLatest then
            "Value" := 'Latest';
        Keys := UncommitedBlocks.Keys;
        foreach "Key" in Keys do
            BlockList.Add("Key", "Value");
    end;

    [NonDebuggable]
    procedure BlockListDictionaryToXmlDocument(BlockList: Dictionary of [Text, Text]): XmlDocument
    var
        Document: XmlDocument;
        BlockListNode: XmlNode;
        BlockNode: XmlNode;
        Keys: List of [Text];
        "Key": Text;
    begin
        XmlDocument.ReadFrom('<?xml version="1.0" encoding="utf-8"?><BlockList></BlockList>', Document);
        Document.SelectSingleNode('/BlockList', BlockListNode);
        Keys := BlockList.Keys;
        foreach "Key" in Keys do begin
            BlockNode := XmlElement.Create(BlockList.Get("Key"), '', "Key").AsXmlNode(); // Dictionary value contains "Latest", "Committed" or "Uncommitted"
            BlockListNode.AsXmlElement().Add(BlockNode);
        end;
        exit(Document);
    end;

    [NonDebuggable]
    procedure TagsDictionaryToXmlDocument(Tags: Dictionary of [Text, Text]): XmlDocument
    var
        Document: XmlDocument;
        TagSetNode: XmlNode;
        TagNode: XmlNode;
        KeyNode: XmlNode;
        ValueNode: XmlNode;
        Keys: List of [Text];
        "Key": Text;
    begin
        XmlDocument.ReadFrom('<?xml version="1.0" encoding="utf-8"?><Tags><TagSet></TagSet></Tags>', Document);
        Document.SelectSingleNode('/Tags/TagSet', TagSetNode);
        Keys := Tags.Keys;
        foreach "Key" in Keys do begin
            TagNode := XmlElement.Create('Tag').AsXmlNode();
            KeyNode := XmlElement.Create('Key', '', "Key").AsXmlNode();
            ValueNode := XmlElement.Create('Value', '', Tags.Get("Key")).AsXmlNode();
            TagSetNode.AsXmlElement().Add(TagNode);

            TagNode.AsXmlElement().Add(KeyNode);
            TagNode.AsXmlElement().Add(ValueNode);
        end;
        exit(Document);
    end;

    [NonDebuggable]
    procedure XmlDocumentToTagsDictionary(Document: XmlDocument): Dictionary of [Text, Text]
    var
        Tags: Dictionary of [Text, Text];
        TagNodesList: XmlNodeList;
        TagNode: XmlNode;
        KeyValue: Text;
        Value: Text;
    begin
        if not Document.SelectNodes('/Tags/TagSet/Tag', TagNodesList) then
            exit;

        foreach TagNode in TagNodesList do begin
            KeyValue := GetSingleNodeInnerText(TagNode, 'Key');
            Value := GetSingleNodeInnerText(TagNode, 'Value');
            if KeyValue = '' then begin
                Clear(Tags);
                exit;
            end;
            Tags.Add(KeyValue, Value);
        end;
        exit(Tags);
    end;

    [NonDebuggable]
    local procedure GetSingleNodeInnerText(Node: XmlNode; XPath: Text): Text
    var
        ChildNode: XmlNode;
        XmlElement: XmlElement;
    begin
        if not Node.SelectSingleNode(XPath, ChildNode) then
            exit;
        XmlElement := ChildNode.AsXmlElement();
        exit(XmlElement.InnerText());
    end;

    [NonDebuggable]
    procedure TagsDictionaryToSearchExpression(Tags: Dictionary of [Text, Text]): Text
    var
        Keys: List of [Text];
        "Key": Text;
        SingleQuoteChar: Char;
        Expression: Text;
        ExpressionPartLbl: Label '"%1" %2 %3%4%5', Comment = '%1 = Tag, %2 = Operator, %3 = Single Quote, %4 = Value, %5 = Single Quote', Locked = true;
    begin
        SingleQuoteChar := 39;
        Keys := Tags.Keys;
        foreach "Key" in Keys do begin
            if Expression <> '' then
                Expression += ' AND ';
            Expression += StrSubstNo(ExpressionPartLbl, "Key".Trim(), GetOperatorFromValue(Tags.Get("Key")).Trim(), SingleQuoteChar, GetValueWithoutOperator(Tags.Get("Key")).Trim(), SingleQuoteChar);
        end;
        exit(Expression);
    end;

    [NonDebuggable]
    procedure QueryExpressionToQueryBlobContent(QueryExpression: Text): XmlDocument
    var
        Document: XmlDocument;
        QueryRequestNode: XmlNode;
        QueryTypeNode: XmlNode;
        ExpressionNode: XmlNode;
    begin
        XmlDocument.ReadFrom('<?xml version="1.0" encoding="utf-8"?><QueryRequest></QueryRequest>', Document);
        Document.SelectSingleNode('/QueryRequest', QueryRequestNode);
        QueryTypeNode := XmlElement.Create('QueryType', '', 'SQL').AsXmlNode();
        QueryRequestNode.AsXmlElement().Add(QueryTypeNode);
        ExpressionNode := XmlElement.Create('Expression', '', QueryExpression).AsXmlNode();
        QueryRequestNode.AsXmlElement().Add(ExpressionNode);
        exit(Document);
    end;

    [NonDebuggable]
    local procedure GetOperatorFromValue("Value": Text): Text
    var
        NewValue: Text;
    begin
        NewValue := "Value".Substring(1, "Value".IndexOf(' '));
        exit(NewValue.Trim());
    end;

    [NonDebuggable]
    local procedure GetValueWithoutOperator("Value": Text): Text
    var
        NewValue: Text;
    begin
        NewValue := "Value".Substring("Value".IndexOf(' ') + 1);
        exit(NewValue.Trim());
    end;

    [NonDebuggable]
    procedure TextToXmlDocument(SourceText: Text): XmlDocument
    var
        Document: XmlDocument;
    begin
        XmlDocument.ReadFrom(SourceText, Document);
        exit(Document);
    end;

    procedure ConvertToDateTime(PropertyValue: Text): DateTime
    var
        NewDateTime: DateTime;
    begin
        NewDateTime := 0DT;
        // PropertyValue is something like the following: 'Mon, 24 May 2021 12:25:27 GMT'
        // 'Evaluate' converts these correctly
        Evaluate(NewDateTime, PropertyValue);
        exit(NewDateTime);
    end;

    procedure ConvertToInteger(PropertyValue: Text): Integer
    var
        NewInteger: Integer;
    begin
        if Evaluate(NewInteger, PropertyValue) then
            exit(NewInteger);
    end;

    procedure ConvertToBoolean(PropertyValue: Text): Boolean
    var
        NewBoolean: Boolean;
    begin
        if Evaluate(NewBoolean, PropertyValue) then
            exit(NewBoolean);
    end;

    procedure ConvertToEnum(FieldName: Text; PropertyValue: Text): Variant
    begin
        if FieldName = 'Resource Type' then
            case PropertyValue of
                Text.LowerCase(Format(Enum::"ABS Blob Resource Type"::File)):
                    exit(Enum::"ABS Blob Resource Type"::File);
                Text.LowerCase(Format(Enum::"ABS Blob Resource Type"::Directory)):
                    exit(Enum::"ABS Blob Resource Type"::Directory);
            end;
    end;

    procedure GetNewLineCharacter(): Text
    var
        LF: Char;
    begin
        LF := 10;
        exit(Format(LF));
    end;

    procedure GetIso8601DateTime(MyDateTime: DateTime): Text
    begin
        exit(FormatDateTime(MyDateTime, 's')); // https://go.microsoft.com/fwlink/?linkid=2210384
    end;

    procedure GetRfc1123DateTime(MyDateTime: DateTime): Text
    begin
        exit(FormatDateTime(MyDateTime, 'R')); // https://go.microsoft.com/fwlink/?linkid=2210384
    end;

    local procedure FormatDateTime(MyDateTime: DateTime; FormatSpecifier: Text): Text
    var
        DateTimeAsXmlString: Text;
        DateTimeDotNet: DotNet DateTime;
    begin
        DateTimeAsXmlString := Format(MyDateTime, 0, 9); // Format as XML, e.g.: 2020-11-11T08:50:07.553Z
        exit(DateTimeDotNet.Parse(DateTimeAsXmlString).ToUniversalTime().ToString(FormatSpecifier));
    end;
}