']);
tempDSName := __DATAREC_NAME + '_' + INTFORMAT(COUNTER, 4, 1);
SELF.eclType := IF(NOT shouldRewriteType, Std.Str.ToUpperCase(LEFT.eclType), tempDSName),
SELF.bestAttributeType := IF(NOT shouldRewriteType, LEFT.bestAttributeType, tempDSName),
SELF.bestAssignment := IF
(
__NeedCoercion(SELF.eclType, SELF.bestAttributeType),
' SELF.' + LEFT.name + ' := (' + Std.Str.ToUppercase(SELF.bestAttributeType) + ')r.' + LEFT.name + ';',
''
),
SELF := LEFT
)
);
LOCAL __LayoutItems := RECORD(__StringRec)
STRING fullName {DEFAULT('')};
STRING bestAssignment {DEFAULT('')};
END;
LOCAL __ChildRecLayout := RECORD
STRING layoutName;
UNSIGNED2 startPos;
UNSIGNED2 endPos;
UNSIGNED2 depth;
DATASET(__LayoutItems) items;
END;
// Function for creating ECL TRANSFORM assignment statements
LOCAL __MakeRecDefinition(DATASET(RECORDOF(__fieldInfo20)) ds, STRING layoutName, BOOLEAN useBest = TRUE) := FUNCTION
displayPrefix := IF(useBest, 'New', 'Old');
displayedLayoutName := displayPrefix + layoutName;
RETURN DATASET([{displayedLayoutName + ' := RECORD'}], __LayoutItems)
& PROJECT
(
DISTRIBUTE(SORT(ds, position), 0),
TRANSFORM
(
__LayoutItems,
attrType := IF(useBest, LEFT.bestAttributeType, LEFT.eclType);
attrPrefix := IF(LEFT.isDataset OR LEFT.isRecord, displayPrefix, '');
fullAttrType := attrPrefix + attrType;
namedDataType := IF(NOT LEFT.isDataset, fullAttrType, 'DATASET(' + fullAttrType + ')');
SELF.s := ' ' + namedDataType + ' ' + LEFT.name + ';',
SELF.bestAssignment := MAP
(
LEFT.bestAssignment != '' => LEFT.bestAssignment,
LEFT.isRecord => ' SELF.' + LEFT.name + ' := ROW(Make_' + fullAttrType + '(r.' + LEFT.name + '));',
LEFT.isDataset => ' SELF.' + LEFT.name + ' := PROJECT(r.' + LEFT.name + ', Make_' + fullAttrType + '(LEFT));',
''
),
SELF := LEFT
)
)
& DATASET([{'END;'}], __LayoutItems);
END;
// Iteratively process embedded records and child dataset definitions,
// extracting each into its own record
LOCAL __ProcessChildRecs(DATASET(__ChildRecLayout) layoutDS, UNSIGNED2 aDepth, BOOLEAN useBest = TRUE) := FUNCTION
__bestNamedChildRecs := DENORMALIZE
(
__fieldInfo20(depth = (aDepth - 1) AND (isRecord OR isDataset)),
__fieldInfo20(depth = aDepth),
RIGHT.position BETWEEN LEFT.position + 1 AND LEFT.endPosition,
GROUP,
TRANSFORM
(
__ChildRecLayout,
SELF.layoutName := LEFT.bestAttributeType,
SELF.items := __MakeRecDefinition(ROWS(RIGHT), SELF.layoutName, useBest),
SELF.startPos := LEFT.position,
SELF.endPos := LEFT.endPosition,
SELF.depth := aDepth,
SELF := LEFT
),
ALL, ORDERED(TRUE)
) : ONWARNING(4531, IGNORE);
RETURN layoutDS + __bestNamedChildRecs;
END;
// Create a list of embedded records and child dataset definitions for the
// original input dataset
LOCAL __oldNamedChildRecs0 := LOOP
(
DATASET([], __ChildRecLayout),
MAX(__fieldInfo20, depth),
__ProcessChildRecs(ROWS(LEFT), MAX(__fieldInfo20, depth) + 1 - COUNTER, FALSE)
);
LOCAL __oldNamedChildRecs := SORT(__oldNamedChildRecs0, endPos, -startPos);
LOCAL __topLevelOldRecDef := DATASET
(
[
{
__LAYOUT_NAME,
0,
0,
0,
__MakeRecDefinition(__fieldInfo20(depth = 0), __LAYOUT_NAME, FALSE)
}
],
__ChildRecLayout
);
LOCAL __allOldRecDefs := __oldNamedChildRecs & __topLevelOldRecDef;
// Create a list of embedded records and child dataset definitions using the
// the recommended ECL datatypes
LOCAL __bestNamedChildRecs0 := LOOP
(
DATASET([], __ChildRecLayout),
MAX(__fieldInfo20, depth),
__ProcessChildRecs(ROWS(LEFT), MAX(__fieldInfo20, depth) + 1 - COUNTER, TRUE)
);
LOCAL __bestNamedChildRecs := SORT(__bestNamedChildRecs0, endPos, -startPos);
LOCAL __topLevelBestRecDef := DATASET
(
[
{
__LAYOUT_NAME,
0,
0,
0,
__MakeRecDefinition(__fieldInfo20(depth = 0), __LAYOUT_NAME, TRUE)
}
],
__ChildRecLayout
);
LOCAL __allBestRecDefs := __bestNamedChildRecs & __topLevelBestRecDef;
// Creates an ECL TRANSFORM function based on the collected information
// about a record definition
LOCAL __MakeTransforms(__ChildRecLayout recInfo) := FUNCTION
RETURN DATASET(['New' + recInfo.layoutName + ' Make_New' + recInfo.layoutName + '(Old' + recInfo.layoutName + ' r) := TRANSFORM'], __StringRec)
& PROJECT
(
DISTRIBUTE(recInfo.items, 0),
TRANSFORM
(
__StringRec,
assignment := LEFT.bestAssignment;
SELF.s := IF(assignment != '', assignment, SKIP)
)
)
& DATASET([' SELF := r;'], __StringRec)
& DATASET(['END;'], __StringRec);
END;
LOCAL __allTransforms := PROJECT
(
__allBestRecDefs,
TRANSFORM
(
{
DATASET(__StringRec) lines
},
SELF.lines := __MakeTransforms(LEFT)
)
);
// Create a dataset of STRINGS that contain record definitions for the
// input dataset, TRANSFORMs for converting between the old and new
// definitions, and a sample PROJECT for kicking it all off
LOCAL __conditionalBR := #IF((BOOLEAN)textOutput) '
' #ELSE '' #END;
LOCAL __oldRecDefsPlusTransforms := DATASET(['//----------' + __conditionalBR], __StringRec)
& PROJECT(__allOldRecDefs.items, __StringRec)
& DATASET(['//----------' + __conditionalBR], __StringRec)
& __allTransforms.lines
& DATASET(['//----------' + __conditionalBR], __StringRec)
& DATASET(['oldDS := DATASET([], OldLayout);' + __conditionalBR], __StringRec)
& DATASET(['newDS := PROJECT(oldDS, Make_NewLayout(LEFT));' + __conditionalBR], __StringRec);
// Combine old definitions and transforms conditionally
LOCAL __conditionalOldStuff :=
#IF((BOOLEAN)emitTransform)
__oldRecDefsPlusTransforms
#ELSE
DATASET([], __StringRec)
#END;
LOCAL __allOutput := PROJECT(__allBestRecDefs.items, __StringRec) & __conditionalOldStuff;
// Roll everything up to one string with HTML line breaks
LOCAL __htmlString := ROLLUP
(
__allOutput,
TRUE,
TRANSFORM
(
RECORDOF(LEFT),
rightString := IF(RIGHT.s = 'END;', RIGHT.s + '
', RIGHT.s);
SELF.s := LEFT.s + '
' + rightString
)
);
// Stuff the HTML result into a single record, wrapped with so it
// looks right in the browser
LOCAL __htmlResult := DATASET(['' + __htmlString[1].s + '
'], {STRING result__html});
// Choose the result (dataset with each line a string, or a text blob)
LOCAL __finalResult := #IF((BOOLEAN)textOutput) __htmlResult #ELSE __allOutput #END;
RETURN __finalResult;
ENDMACRO;