Skip to content

Commit

Permalink
Convert structures and tables to AbapValue (#195)
Browse files Browse the repository at this point in the history
convert structures and tables to AbapValues
  • Loading branch information
fw2568 committed Nov 7, 2022
1 parent da04bd6 commit db7ed40
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 1 deletion.
3 changes: 3 additions & 0 deletions YaNco.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Abap/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dbosoft/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ public Handler(IRfcContext rfcContext, IConfiguration configuration)


}

public int Invoke(InvocationContext context)
{
throw new NotImplementedException();
}

public Task<int> InvokeAsync(InvocationContext context)
{
return _rfcContext.CallFunction("BAPI_SALESDOCU_CREATEFROMDATA1",
Expand Down
2 changes: 2 additions & 0 deletions src/YaNco.Core/TypeMapping/DefaultConverterResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public class DefaultConverterResolver : IRfcConverterResolver
{
typeof(DateTimeValueConverter),
typeof(ByteValueConverter),
typeof(DictionaryFromAbapStructureValueConverter),
typeof(ListFromAbapTableValueConverter),
typeof(DefaultFromAbapValueConverter<>),
});

Expand Down
10 changes: 10 additions & 0 deletions src/YaNco.Core/TypeMapping/DefaultFieldMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ public DefaultFieldMapper(IRfcConverterResolver converterResolver)
case RfcType.XSTRING:
return context.RfcRuntime.GetBytes(context.Handle, context.FieldInfo.Name).Map(v =>
(AbapValue) new AbapByteValue(context.FieldInfo, v));
case RfcType.STRUCTURE:
return context.RfcRuntime.GetStructure(context.Handle, context.FieldInfo.Name)
.Map(handle => (IStructure)new Structure(handle, context.RfcRuntime))
.Bind(s => s.ToDictionary())
.Map(d => (AbapValue)new AbapStructureValues(context.FieldInfo, d));
case RfcType.TABLE:
return context.RfcRuntime.GetTable(context.Handle, context.FieldInfo.Name)
.Map(handle => (ITable)new Table(handle, context.RfcRuntime))
.MapStructure(d => d.ToDictionary())
.Map(tr => (AbapValue)new AbapTableValues(context.FieldInfo, tr));
default:
throw new NotSupportedException(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using LanguageExt;

namespace Dbosoft.YaNco.TypeMapping
{
public class DictionaryFromAbapStructureValueConverter : IFromAbapValueConverter<IDictionary<string, AbapValue>>
{
public Try<IDictionary<string, AbapValue>> ConvertTo(AbapValue abapValue)
{
return Prelude.Try(() =>
{
if (!(abapValue is AbapStructureValues structure))
throw new InvalidCastException(
$"cannot convert type of {abapValue.GetType()} to {nameof(AbapStructureValues)}");
return structure.Values;
}

);
}

public bool CanConvertTo(RfcType rfcType)
{

// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (rfcType)
{
case RfcType.STRUCTURE:
return true;
default:
return false;
}
}
}
}
36 changes: 36 additions & 0 deletions src/YaNco.Core/TypeMapping/ListFromAbapTableValueConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using LanguageExt;

namespace Dbosoft.YaNco.TypeMapping
{
public class ListFromAbapTableValueConverter : IFromAbapValueConverter<IEnumerable<IDictionary<string, AbapValue>>>
{
public Try<IEnumerable<IDictionary<string, AbapValue>>> ConvertTo(AbapValue abapValue)
{
return Prelude.Try(() =>
{
if (!(abapValue is AbapTableValues table))
throw new InvalidCastException(
$"cannot convert type of {abapValue.GetType()} to {nameof(AbapTableValues)}");
return table.Values;
}

);
}

public bool CanConvertTo(RfcType rfcType)
{

// ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
switch (rfcType)
{
case RfcType.TABLE:
return true;
default:
return false;
}
}
}
}
16 changes: 16 additions & 0 deletions src/YaNco.Primitives/TypeMapping/AbapStructureValues.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;

namespace Dbosoft.YaNco.TypeMapping
{
public class AbapStructureValues : AbapValue
{
public readonly IDictionary<string, AbapValue> Values;

public AbapStructureValues(RfcFieldInfo fieldInfo, IDictionary<string, AbapValue> values) :
base(fieldInfo)
{
Values = values;
}
}
}
15 changes: 15 additions & 0 deletions src/YaNco.Primitives/TypeMapping/AbapTableValues.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;

namespace Dbosoft.YaNco.TypeMapping
{
public class AbapTableValues : AbapValue
{
public readonly IEnumerable<IDictionary<string, AbapValue>> Values;

public AbapTableValues(RfcFieldInfo fieldInfo, IEnumerable<IDictionary<string, AbapValue>> values) :
base(fieldInfo)
{
Values = values;
}
}
}
107 changes: 107 additions & 0 deletions test/SAPSystemTests/AbapValueJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using Dbosoft.YaNco;
using Dbosoft.YaNco.TypeMapping;

namespace SAPSystemTests
{
public class AbapValueJsonConverter : JsonConverter<AbapValue>
{
public IFieldMapper FieldMapper;

public AbapValueJsonConverter(IFieldMapper fieldMapper)
{
FieldMapper = fieldMapper;
}

public override AbapValue Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
throw new NotImplementedException();


public override void Write(
Utf8JsonWriter writer,
AbapValue value,
JsonSerializerOptions options)
{

switch (value.FieldInfo.Type)
{
case RfcType.NUM:
case RfcType.INT8:
case RfcType._UTCLONG:
case RfcType.UTCSECOND:
case RfcType.UTCMINUTE:
case RfcType.DTDAY:
case RfcType._DTWEEK:
case RfcType.DTMONTH:
case RfcType.TSECOND:
case RfcType.TMINUTE:
case RfcType.CDAY:
case RfcType.INT:
case RfcType.INT2:
case RfcType.INT1:
FieldMapper.FromAbapValue<long>(value)
.Match(writer.WriteNumberValue
, l => throw new Exception(l.Message));
break;
case RfcType.DECF16:
case RfcType.DECF34:
FieldMapper.FromAbapValue<decimal>(value)
.Match(writer.WriteNumberValue
, l => throw new Exception(l.Message));
break;
case RfcType.FLOAT:
FieldMapper.FromAbapValue<float>(value)
.Match(writer.WriteNumberValue
, l => throw new Exception(l.Message));
break;
case RfcType.XSTRING:
case RfcType.BYTE:
FieldMapper.FromAbapValue<byte[]>(value)
.Match(b => writer.WriteBase64StringValue(new ReadOnlySpan<byte>(b))
, l => throw new Exception(l.Message));
break;

case RfcType.TIME:
case RfcType.DATE:
case RfcType.CHAR:
case RfcType.STRING:
FieldMapper.FromAbapValue<string>(value)
.Match(writer.WriteStringValue
, l => throw new Exception(l.Message));
break;

case RfcType.BCD:
break;
case RfcType.NULL:
break;
case RfcType.ABAPOBJECT:
break;
case RfcType.STRUCTURE:
FieldMapper.FromAbapValue<IDictionary<string, AbapValue>>(value)
.Match(
d => JsonSerializer.Serialize(writer, d, options),
l => throw new Exception(l.Message));
break;
case RfcType.TABLE:
FieldMapper.FromAbapValue<IEnumerable<IDictionary<string, AbapValue>>>(value)
.Match(
ed => JsonSerializer.Serialize(writer, ed, options),
l => throw new Exception(l.Message));
break;
case RfcType.XMLDATA:
break;
case RfcType.BOX:
break;
case RfcType.GENERIC_BOX:
break;
}

}
}
}
35 changes: 34 additions & 1 deletion test/SAPSystemTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Dbosoft.YaNco;
Expand Down Expand Up @@ -97,6 +98,7 @@ private static async Task RunIntegrationTests(IRfcContext context)

await RunIntegrationTest01(context);
await RunIntegrationTest02(context);
await RunIntegrationTest03(context);

Console.WriteLine("*** END OF Integration Tests ***");
}
Expand Down Expand Up @@ -132,7 +134,7 @@ private static async Task RunIntegrationTest01(IRfcContext context)
UNIT = "ABC"
};

var outputData = await context.CallFunction("ZYANCO_IT_1",
var outputData = await context.CallFunction("ZYANCO_it_1",
Input: f => f.SetStructure("IS_IN",
s => s
.SetField("FIELD_ACCP", inputData.ACCP)
Expand Down Expand Up @@ -375,6 +377,36 @@ private static async Task RunIntegrationTest02(IRfcContext context)
}


private static async Task RunIntegrationTest03(IRfcContext context)
{
Console.WriteLine("Integration Tests 03 (read deep structure, convert to json)");
var expected =
"{\"CHAR01\":\"A\",\"CHAR03\":\"ABC\",\"STRUCT\":{\"CHAR01\":\"A\",\"CHAR03\":\"ABC\"},\"TAB\":[{\"CHAR01\":\"A\",\"CHAR03\":\"ABC\"}]}";

await (from output in context.CallFunction("ZYANCO_IT_4",
Input: f => f,
Output: f => f.MapStructure("ES_DEEP", s =>
s.ToDictionary())

)
from connection in context.GetConnection()
select (Values: output, Connection: connection))
.Match(
r =>
{
var jsonOptions = new JsonSerializerOptions();
jsonOptions.Converters.Add(new AbapValueJsonConverter(r.Connection.RfcRuntime.FieldMapper));
var json = JsonSerializer.Serialize(r.Values, jsonOptions);
Console.WriteLine(json == expected ? "Test succeed" : "Test failed");
},
l =>
{
Console.WriteLine(l.Message);
});
}



private static async Task<long> RunPerformanceTest01(IRfcContext context, int rows = 0)
{
var watch = Stopwatch.StartNew();
Expand Down Expand Up @@ -498,4 +530,5 @@ public class TypesTestData


}

}

0 comments on commit db7ed40

Please sign in to comment.