Skip to content

Commit

Permalink
Handle projection in json or anydata array
Browse files Browse the repository at this point in the history
  • Loading branch information
prakanth97 committed Mar 21, 2024
1 parent ccd9687 commit 33eb1c6
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 11 deletions.
32 changes: 32 additions & 0 deletions ballerina/tests/fromXml_test.bal
Original file line number Diff line number Diff line change
Expand Up @@ -2753,6 +2753,38 @@ function testAddingContentFieldWhenRestTypeAsExpTypeForFromXmlWithType() returns
test:assertEquals(val2.B, {C: {\#content: 3, c: "attribute_c"}});
}

type ProjectionRec1 record {|
json[1] Employee;
anydata[2] Departments;
|};

@test:Config
function testProjectionWithJsonArrayOrAnydataArrayForFromXmlStringWithType() returns error? {
string xmlStr = string `<Company>
<Employee age="30">
<Name>John Doe</Name>
</Employee>
<Employee age="26">
<Name>Walter White</Name>
</Employee>
<Departments>Engineering</Departments>
<Departments>Hr</Departments>
<Departments>Customer Success</Departments>
</Company>`;
record {
json[1] Employee;
anydata[2] Departments;
} rec = check fromXmlStringWithType(xmlStr);
test:assertEquals(rec.length(), 2);
test:assertEquals(rec.Employee, [
{
"Name": "John Doe",
"age": 30
}
]);
test:assertEquals(rec.Departments, ["Engineering", "Hr"]);
}

// Negative cases
type DataN1 record {|
int A;
Expand Down
123 changes: 123 additions & 0 deletions ballerina/tests/from_xml_with_options.bal
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,129 @@ function testDisableProjectionForFromXmlWithTypeNegative() returns error? {
test:assertEquals((<error>e5).message(), "undefined field '#content' in record 'data.xmldata:record {| int age; |}'");
}

type IntArray int[2];
type StringArray string[3];
type Record1 record {|
IntArray A;
StringArray B;
|};

@test:Config
function testDisableProjectionInArrayForFromXmlStringWithTypeNegative() {
string xmlStr = string `<DataProj>
<A><B>1</B></A>
<A><B>2</B></A>
<A><B>3</B></A>
</DataProj>`;
DataProj|Error err1 = fromXmlStringWithType(xmlStr, sOptions3);
test:assertTrue(err1 is Error);
test:assertEquals((<error> err1).message(), "array size is not compatible with the expected size");

string xmlStr2 = string `
<Data>
<A>1</A>
<A>2</A>
<A>3</A>
<B>Kevin</B>
<B>Violet</B>
<B>Tommy</B>
</Data>
`;
Record1|Error err2 = fromXmlStringWithType(xmlStr2, sOptions3);
test:assertTrue(err2 is Error);
test:assertEquals((<error> err2).message(), "array size is not compatible with the expected size");

string xmlStr3 = string `
<Data>
<A>1</A>
<A>2</A>
<B>Kevin</B>
<B>Violet</B>
<B>Tommy</B>
<B>James</B>
</Data>
`;
Record1|Error err3 = fromXmlStringWithType(xmlStr3, sOptions3);
test:assertTrue(err3 is Error);
test:assertEquals((<error> err3).message(), "array size is not compatible with the expected size");

string xmlStr4 = string `<Company>
<Employee age="30">
<Name>John Doe</Name>
</Employee>
<Employee age="26">
<Name>Walter White</Name>
</Employee>
<Departments>Engineering</Departments>
<Departments>Hr</Departments>
<Departments>Customer Success</Departments>
</Company>`;
record {
json[1] Employee;
anydata[2] Departments;
}|error rec = fromXmlStringWithType(xmlStr4, sOptions3);
test:assertTrue(rec is error);
test:assertEquals((<error>rec).message(), "array size is not compatible with the expected size");
}

@test:Config
function testDisableProjectionInArrayForFromXmlWithTypeNegative() {
xml xmlVal1 = xml `<DataProj>
<A><B>1</B></A>
<A><B>2</B></A>
<A><B>3</B></A>
</DataProj>`;
DataProj|Error err1 = fromXmlWithType(xmlVal1, sOptions3);
test:assertTrue(err1 is Error);
test:assertEquals((<error> err1).message(), "array size is not compatible with the expected size");

xml xmlVal2 = xml `
<Data>
<A>1</A>
<A>2</A>
<A>3</A>
<B>Kevin</B>
<B>Violet</B>
<B>Tommy</B>
</Data>
`;
Record1|Error err2 = fromXmlWithType(xmlVal2, sOptions3);
test:assertTrue(err2 is Error);
test:assertEquals((<error> err2).message(), "array size is not compatible with the expected size");

xml xmlVal3 = xml `
<Data>
<A>1</A>
<A>2</A>
<B>Kevin</B>
<B>Violet</B>
<B>Tommy</B>
<B>James</B>
</Data>
`;
Record1|Error err3 = fromXmlWithType(xmlVal3, sOptions3);
test:assertTrue(err3 is Error);
test:assertEquals((<error> err3).message(), "array size is not compatible with the expected size");

xml xmlVal4 = xml `<Company>
<Employee age="30">
<Name>John Doe</Name>
</Employee>
<Employee age="26">
<Name>Walter White</Name>
</Employee>
<Departments>Engineering</Departments>
<Departments>Hr</Departments>
<Departments>Customer Success</Departments>
</Company>`;
record {
json[1] Employee;
anydata[2] Departments;
}|error rec = fromXmlWithType(xmlVal4, sOptions3);
test:assertTrue(rec is error);
test:assertEquals((<error>rec).message(), "array size is not compatible with the expected size");
}

SourceOptions sOptions6 = {attributePrefix: "@", allowDataProjection: false, textFieldName: "value"};

type Library record {|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ private void validateExpectedType(TypeSymbol typeSymbol, Optional<Location> loca
case UNION -> {
int nonErrorTypeCount = 0;
for (TypeSymbol memberTSymbol : ((UnionTypeSymbol) typeSymbol).memberTypeDescriptors()) {
if (memberTSymbol.typeKind() == TypeDescKind.ERROR) {
if (getReferredTypeSymbol(memberTSymbol).typeKind() == TypeDescKind.ERROR) {
continue;
}
nonErrorTypeCount++;
Expand All @@ -162,6 +162,13 @@ private void validateExpectedType(TypeSymbol typeSymbol, Optional<Location> loca
}
}

private TypeSymbol getReferredTypeSymbol(TypeSymbol typeSymbol) {
if (typeSymbol.typeKind() == TypeDescKind.TYPE_REFERENCE) {
return ((TypeReferenceTypeSymbol) typeSymbol).typeDescriptor();
}
return typeSymbol;
}

private boolean isNotValidExpectedType(TypeSymbol typeSymbol) {
switch (typeSymbol.typeKind()) {
case RECORD -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,12 @@ public static QualifiedName getElementName(QName qName) {

public static Object convertStringToExpType(BString value, Type expType) {
Object result;
switch (expType.getTag()) {
Type refferedType = TypeUtils.getReferredType(expType);
switch (refferedType.getTag()) {
case TypeTags.ANYDATA_TAG, TypeTags.ANY_TAG, TypeTags.JSON_TAG ->
result = FromString.fromStringWithType(value, PredefinedTypes.TYPE_JSON);
case TypeTags.ARRAY_TAG -> result = convertStringToExpType(value, ((ArrayType) expType).getElementType());
case TypeTags.ARRAY_TAG -> result = convertStringToExpType(value,
((ArrayType) refferedType).getElementType());
default -> result = FromString.fromStringWithType(value, expType);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ private void addTextToCurrentNodeIfExpTypeIsArray(ArrayType fieldType, BString b
bText, xmlParserData);
case TypeTags.ANYDATA_TAG, TypeTags.JSON_TAG -> {
BArray tempArr = (BArray) ((BMap<BString, Object>) xmlParserData.nodesStack.peek()).get(bFieldName);
Object nextValue = tempArr.get(tempArr.getLength() - 1);
if (!(nextValue instanceof BMap)) {
return;
}
tempArr.add(tempArr.getLength() - 1, convertStringToRestExpType(bText, fieldType));
}
}
Expand Down Expand Up @@ -524,7 +528,7 @@ private void updateNextArrayMember(XMLStreamReader xmlStreamReader, XmlParserDat
case TypeTags.RECORD_TYPE_TAG -> updateNextRecord(xmlStreamReader, xmlParserData, fieldName,
fieldType, (RecordType) type);
case TypeTags.MAP_TAG, TypeTags.ANYDATA_TAG, TypeTags.JSON_TAG ->
updateNextMap(xmlParserData, fieldName, type);
updateNextMap(xmlParserData, fieldName, fieldType);
}
}

Expand All @@ -538,12 +542,17 @@ private void updateNextMap(XmlParserData xmlParserData, String fieldName, Type f

private BMap<BString, Object> updateNextMapValue(XmlParserData xmlParserData, String fieldName, Type fieldType) {
BMap<BString, Object> nextValue;
if (fieldType.getTag() == TypeTags.MAP_TAG) {
nextValue = ValueCreator.createMapValue((MapType) fieldType);
xmlParserData.restTypes.push(((MapType) fieldType).getConstrainedType());
Type type = fieldType;
if (fieldType.getTag() == TypeTags.ARRAY_TAG) {
type = ((ArrayType) fieldType).getElementType();
}

if (type.getTag() == TypeTags.MAP_TAG) {
nextValue = ValueCreator.createMapValue((MapType) type);
xmlParserData.restTypes.push(((MapType) type).getConstrainedType());
} else {
nextValue = ValueCreator.createMapValue(TypeCreator.createMapType(fieldType));
xmlParserData.restTypes.push(fieldType);
nextValue = ValueCreator.createMapValue(TypeCreator.createMapType(type));
xmlParserData.restTypes.push(type);
}

xmlParserData.attributeHierarchy.push(new HashMap<>());
Expand All @@ -552,7 +561,7 @@ private BMap<BString, Object> updateNextMapValue(XmlParserData xmlParserData, St
BMap<BString, Object> currentNode = xmlParserData.currentNode;
Object temp = currentNode.get(StringUtils.fromString(fieldName));
if (temp instanceof BArray) {
int arraySize = ((ArrayType) TypeUtils.getType(temp)).getSize();
int arraySize = getArraySize(fieldType, temp);
if (arraySize > ((BArray) temp).getLength() || arraySize == -1) {
((BArray) temp).append(nextValue);
} else {
Expand All @@ -565,6 +574,11 @@ private BMap<BString, Object> updateNextMapValue(XmlParserData xmlParserData, St
return nextValue;
}

private int getArraySize(Type type, Object temp) {
return type.getTag() == TypeTags.ARRAY_TAG ?
((ArrayType) type).getSize() : ((ArrayType) TypeUtils.getType(temp)).getSize();
}

private void updateNextRecord(XMLStreamReader xmlStreamReader, XmlParserData xmlParserData, String fieldName,
Type fieldType, RecordType recordType) {
xmlParserData.parents.push(xmlParserData.siblings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ private void convertText(String text, XmlAnalyzerData analyzerData) {
}

BString fieldName = StringUtils.fromString(currentField.getFieldName());
Type fieldType = currentField.getFieldType();
Type fieldType = TypeUtils.getReferredType(currentField.getFieldType());

Object convertedValue = DataUtils.convertStringToExpType(StringUtils.fromString(text), fieldType);
if (mapValue.containsKey(fieldName)) {
Expand Down

0 comments on commit 33eb1c6

Please sign in to comment.