@@ -66,6 +66,92 @@ public async Task JsonSerializeUOTest()
6666 yield return ( 20 , new TestUO ( 123456789012345.6789012345678m ) , @"""123456789012345.6789012345678""" ) ;
6767 }
6868
69+ [ Fact ]
70+ public async Task JsonSerializeUOWithFlattenValueTablesTest ( )
71+ {
72+ PowerFxConfig config = new PowerFxConfig ( ) ;
73+ config . EnableJsonFunctions ( ) ;
74+
75+ SymbolTable symbolTable = new SymbolTable ( ) ;
76+ ISymbolSlot objSlot = symbolTable . AddVariable ( "obj" , FormulaType . UntypedObject ) ;
77+ RecalcEngine engine = new RecalcEngine ( config ) ;
78+
79+ // Test 1: Single-column "Value" table should be flattened
80+ var singleColumnValueArray = new [ ]
81+ {
82+ new { Value = 1 } ,
83+ new { Value = 2 } ,
84+ new { Value = 3 }
85+ } ;
86+
87+ SymbolValues symbolValues1 = new SymbolValues ( symbolTable ) ;
88+ symbolValues1 . Set ( objSlot , FormulaValue . New ( new TestUO ( singleColumnValueArray ) ) ) ;
89+ RuntimeConfig runtimeConfig1 = new RuntimeConfig ( symbolValues1 ) ;
90+
91+ // With FlattenValueTables - should flatten to [1,2,3]
92+ FormulaValue fv1 = await engine . EvalAsync ( "JSON(obj, JSONFormat.FlattenValueTables)" , CancellationToken . None , runtimeConfig : runtimeConfig1 ) ;
93+ Assert . IsNotType < ErrorValue > ( fv1 ) ;
94+ string str1 = fv1 . ToExpression ( ) . ToString ( ) ;
95+ Assert . Equal ( @"""[1,2,3]""" , str1 ) ;
96+
97+ // Without FlattenValueTables - should keep structure
98+ FormulaValue fv2 = await engine . EvalAsync ( "JSON(obj)" , CancellationToken . None , runtimeConfig : runtimeConfig1 ) ;
99+ Assert . IsNotType < ErrorValue > ( fv2 ) ;
100+ string str2 = fv2 . ToExpression ( ) . ToString ( ) ;
101+ Assert . Equal ( @"""[{""""Value"""":1},{""""Value"""":2},{""""Value"""":3}]""" , str2 ) ;
102+
103+ // Test 2: Multi-column table should NOT be flattened even with FlattenValueTables
104+ var multiColumnArray = new [ ]
105+ {
106+ new { a = 1 , b = 2 } ,
107+ new { a = 3 , b = 4 }
108+ } ;
109+
110+ SymbolValues symbolValues2 = new SymbolValues ( symbolTable ) ;
111+ symbolValues2 . Set ( objSlot , FormulaValue . New ( new TestUO ( multiColumnArray ) ) ) ;
112+ RuntimeConfig runtimeConfig2 = new RuntimeConfig ( symbolValues2 ) ;
113+
114+ FormulaValue fv3 = await engine . EvalAsync ( "JSON(obj, JSONFormat.FlattenValueTables)" , CancellationToken . None , runtimeConfig : runtimeConfig2 ) ;
115+ Assert . IsNotType < ErrorValue > ( fv3 ) ;
116+ string str3 = fv3 . ToExpression ( ) . ToString ( ) ;
117+ Assert . Equal ( @"""[{""""a"""":1,""""b"""":2},{""""a"""":3,""""b"""":4}]""" , str3 ) ;
118+
119+ // Test 3: Test with null/blank values in Value column
120+ var arrayWithNulls = new [ ]
121+ {
122+ new { Value = ( int ? ) 1 } ,
123+ new { Value = ( int ? ) null } ,
124+ new { Value = ( int ? ) 3 }
125+ } ;
126+
127+ SymbolValues symbolValues3 = new SymbolValues ( symbolTable ) ;
128+ symbolValues3 . Set ( objSlot , FormulaValue . New ( new TestUO ( arrayWithNulls ) ) ) ;
129+ RuntimeConfig runtimeConfig3 = new RuntimeConfig ( symbolValues3 ) ;
130+
131+ FormulaValue fv4 = await engine . EvalAsync ( "JSON(obj, JSONFormat.FlattenValueTables)" , CancellationToken . None , runtimeConfig : runtimeConfig3 ) ;
132+ Assert . IsNotType < ErrorValue > ( fv4 ) ;
133+ string str4 = fv4 . ToExpression ( ) . ToString ( ) ;
134+ Assert . Equal ( @"""[1,null,3]""" , str4 ) ;
135+
136+ // Test 4: Mixed array with multi-column object first, then single-column Value objects
137+ var mixedArray = new object [ ]
138+ {
139+ new { Value = 2 , Value2 = 22 } ,
140+ new { Value = 1 } ,
141+ new { Value = 3 }
142+ } ;
143+
144+ SymbolValues symbolValues4 = new SymbolValues ( symbolTable ) ;
145+ symbolValues4 . Set ( objSlot , FormulaValue . New ( new TestUO ( mixedArray ) ) ) ;
146+ RuntimeConfig runtimeConfig4 = new RuntimeConfig ( symbolValues4 ) ;
147+
148+ FormulaValue fv5 = await engine . EvalAsync ( "JSON(obj, JSONFormat.FlattenValueTables)" , CancellationToken . None , runtimeConfig : runtimeConfig4 ) ;
149+ Assert . IsNotType < ErrorValue > ( fv5 ) ;
150+ string str5 = fv5 . ToExpression ( ) . ToString ( ) ;
151+ // Should flatten only the single-property Value objects, keep the multi-property object as-is
152+ Assert . Equal ( @"""[{""""Value"""":2,""""Value2"""":22},1,3]""" , str5 ) ;
153+ }
154+
69155 public class TestUO : IUntypedObject
70156 {
71157 private enum UOType
0 commit comments