55using System . Collections ;
66using System . Collections . Generic ;
77using System . ComponentModel ;
8+ using System . Diagnostics ;
89using System . Diagnostics . CodeAnalysis ;
910using System . Globalization ;
1011using System . Linq ;
@@ -387,6 +388,80 @@ public static bool TryParseList(object value, out IList list)
387388 return isList ;
388389 }
389390
391+ /// <summary>
392+ /// Try to coerce object to IList.
393+ /// </summary>
394+ /// <param name="value">Value to coerce.</param>
395+ /// <param name="list">IList if found.</param>
396+ /// <returns>true if found IList.</returns>
397+ public static bool TryAsList ( object value , out IEnumerable list )
398+ {
399+ var isList = false ;
400+ list = null ;
401+ if ( value is IList listValue )
402+ {
403+ list = listValue ;
404+ isList = true ;
405+ }
406+ else if ( value is JsonArray jarray )
407+ {
408+ list = jarray ;
409+ isList = true ;
410+ }
411+
412+ return isList ;
413+ }
414+
415+ public static int GetListCount ( IEnumerable list )
416+ {
417+ if ( list is IList listValue )
418+ {
419+ return listValue . Count ;
420+ }
421+ else if ( list is JsonArray jarray )
422+ {
423+ return jarray . Count ;
424+ }
425+
426+ throw new InvalidOperationException ( ) ;
427+ }
428+
429+ public static void AppendToList ( IEnumerable list , object value )
430+ {
431+ if ( list is IList ilist )
432+ {
433+ ilist . Add ( value ) ;
434+ }
435+ else if ( list is JsonArray jarray )
436+ {
437+ JsonValue jvalue = value as JsonValue ;
438+ if ( jvalue == null )
439+ {
440+ jvalue = JsonValue . Create ( value ) ;
441+ }
442+
443+ jarray . Add ( jvalue ) ;
444+ }
445+ }
446+
447+ public static void SetIndex ( IEnumerable list , int idx , object value )
448+ {
449+ if ( list is IList ilist )
450+ {
451+ ilist [ idx ] = value ;
452+ }
453+ else if ( list is JsonArray jarray )
454+ {
455+ JsonValue jvalue = value as JsonValue ;
456+ if ( jvalue == null )
457+ {
458+ jvalue = JsonValue . Create ( value ) ;
459+ }
460+
461+ jarray [ idx ] = jvalue ;
462+ }
463+ }
464+
390465 /// <summary>
391466 /// Verify value is an integer.
392467 /// </summary>
@@ -991,6 +1066,12 @@ internal static object ResolveValue(object obj)
9911066 case JsonValueKind . String :
9921067 return jval . GetString ( ) ;
9931068 case JsonValueKind . Number :
1069+ // If this is a JsonElement we can get back int vs floating point from it, so try that first
1070+ if ( jval . TryGetValue < JsonElement > ( out var jelem ) )
1071+ {
1072+ return ResolveValue ( jelem ) ;
1073+ }
1074+
9941075 return jval . GetNumber ( ) ;
9951076 case JsonValueKind . Null :
9961077 return null ;
@@ -1004,40 +1085,41 @@ internal static object ResolveValue(object obj)
10041085 }
10051086 else if ( obj is JsonElement jelem )
10061087 {
1007- switch ( jelem . ValueKind )
1008- {
1009- case JsonValueKind . String :
1010- return jelem . GetString ( ) ;
1011- case JsonValueKind . Number :
1012- if ( jelem . TryGetInt32 ( out var int32 ) )
1013- {
1014- return int32 ;
1015- }
1016- else if ( jelem . TryGetInt64 ( out var int64 ) )
1017- {
1018- return int64 ;
1019- }
1020- else if ( jelem . TryGetDecimal ( out var dec ) )
1021- {
1022- return dec ;
1023- }
1024-
1025- return jelem . GetSingle ( ) ;
1026- case JsonValueKind . Null :
1027- return null ;
1028- case JsonValueKind . True :
1029- return true ;
1030- case JsonValueKind . False :
1031- return false ;
1032- default :
1033- Environment . FailFast ( "Unhandled JsonValueKind" ) ;
1034- return null ;
1035- }
1088+ return ResolveValue ( jelem ) ;
10361089 }
10371090
10381091 return obj ;
10391092 }
10401093
1094+ internal static object ResolveValue ( JsonElement jelem )
1095+ {
1096+ switch ( jelem . ValueKind )
1097+ {
1098+ case JsonValueKind . String :
1099+ return jelem . GetString ( ) ;
1100+ case JsonValueKind . Number :
1101+ if ( jelem . TryGetInt32 ( out var int32 ) )
1102+ {
1103+ return int32 ;
1104+ }
1105+ else if ( jelem . TryGetInt64 ( out var int64 ) )
1106+ {
1107+ return int64 ;
1108+ }
1109+
1110+ return jelem . GetDecimal ( ) ;
1111+ case JsonValueKind . Null :
1112+ return null ;
1113+ case JsonValueKind . True :
1114+ return true ;
1115+ case JsonValueKind . False :
1116+ return false ;
1117+ default :
1118+ Environment . FailFast ( "Unhandled JsonValueKind" ) ;
1119+ return null ;
1120+ }
1121+ }
1122+
10411123 internal static ( object value , string error ) WrapGetValue ( IMemory memory , string property , Options options )
10421124 {
10431125 if ( memory . TryGetValue ( property , out var result ) && result != null )
@@ -1446,11 +1528,11 @@ internal static EvaluateExpressionDelegate SortBy(bool isDescending)
14461528 {
14471529 if ( isDescending )
14481530 {
1449- result = list . OfType < object > ( ) . OrderByDescending ( item => item ) . ToList ( ) ;
1531+ result = list . OfType < object > ( ) . OrderByDescending ( item => item , JsonObjectComparer . Instance ) . ToList ( ) ;
14501532 }
14511533 else
14521534 {
1453- result = list . OfType < object > ( ) . OrderBy ( item => item ) . ToList ( ) ;
1535+ result = list . OfType < object > ( ) . OrderBy ( item => item , JsonObjectComparer . Instance ) . ToList ( ) ;
14541536 }
14551537 }
14561538 else
@@ -1465,11 +1547,11 @@ internal static EvaluateExpressionDelegate SortBy(bool isDescending)
14651547 propertyName = propertyName ?? string . Empty ;
14661548 if ( isDescending )
14671549 {
1468- result = jsonArray . OrderByDescending ( obj => obj [ propertyName ] , JsonNodeComparer . Instance ) . ToList ( ) ;
1550+ result = jsonArray . OrderByDescending ( obj => obj [ propertyName ] , JsonObjectComparer . Instance ) . ToList ( ) ;
14691551 }
14701552 else
14711553 {
1472- result = jsonArray . OrderBy ( obj => obj [ propertyName ] , JsonNodeComparer . Instance ) . ToList ( ) ;
1554+ result = jsonArray . OrderBy ( obj => obj [ propertyName ] , JsonObjectComparer . Instance ) . ToList ( ) ;
14731555 }
14741556 }
14751557 }
@@ -1528,14 +1610,15 @@ private static (object, string) ParseISOTimestamp(string timeStamp, Func<DateTim
15281610 styles : DateTimeStyles . RoundtripKind ,
15291611 result : out var parsed ) )
15301612 {
1531- if ( parsed . ToString ( DefaultDateTimeFormat , CultureInfo . InvariantCulture ) . Equals ( timeStamp , StringComparison . OrdinalIgnoreCase ) )
1532- {
1533- ( result , error ) = transform != null ? transform ( parsed ) : ( parsed , null ) ;
1534- }
1535- else
1536- {
1537- error = $ "{ timeStamp } is not standard ISO format.";
1538- }
1613+ ( result , error ) = transform != null ? transform ( parsed ) : ( parsed , null ) ;
1614+ //if (parsed.ToString(DefaultDateTimeFormat, CultureInfo.InvariantCulture).Equals(timeStamp, StringComparison.OrdinalIgnoreCase))
1615+ //{
1616+ // (result, error) = transform != null ? transform(parsed) : (parsed, null);
1617+ //}
1618+ //else
1619+ //{
1620+ // error = $"{timeStamp} is not standard ISO format.";
1621+ //}
15391622 }
15401623 else
15411624 {
@@ -1582,11 +1665,59 @@ private static int GetPropertyCount(object obj)
15821665 return - 1 ;
15831666 }
15841667
1585- private class JsonNodeComparer : IComparer < JsonNode >
1668+ private class JsonObjectComparer : IComparer < JsonNode > , IComparer < object >
15861669 {
1587- public static readonly JsonNodeComparer Instance = new JsonNodeComparer ( ) ;
1670+ public static readonly JsonObjectComparer Instance = new JsonObjectComparer ( ) ;
1671+
1672+ public int Compare ( JsonNode x , JsonNode y )
1673+ {
1674+ var xkind = x . GetValueKind ( ) ;
1675+ var ykind = y . GetValueKind ( ) ;
1676+ if ( xkind == ykind )
1677+ {
1678+ if ( xkind == JsonValueKind . Number )
1679+ {
1680+ return x . AsValue ( ) . GetValue < decimal > ( ) . CompareTo ( y . AsValue ( ) . GetValue < decimal > ( ) ) ;
1681+ }
1682+ else if ( xkind == JsonValueKind . String )
1683+ {
1684+ return string . CompareOrdinal ( x . AsValue ( ) . GetString ( ) , y . AsValue ( ) . GetString ( ) ) ;
1685+ }
1686+ }
1687+
1688+ return xkind . CompareTo ( ykind ) ;
1689+ }
1690+
1691+ public int Compare ( object x , object y )
1692+ {
1693+ if ( x is JsonNode xj && y is JsonNode yj )
1694+ {
1695+ return Compare ( xj , yj ) ;
1696+ }
1697+ else if ( x is string xs && y is string ys )
1698+ {
1699+ return string . CompareOrdinal ( xs , ys ) ;
1700+ }
1701+ else if ( x is IComparable xc && y is IComparable yc )
1702+ {
1703+ return xc . CompareTo ( yc ) ;
1704+ }
1705+
1706+ if ( x == null && y == null )
1707+ {
1708+ return 0 ;
1709+ }
1710+ else if ( x == null && y != null )
1711+ {
1712+ return - 1 ;
1713+ }
1714+ else if ( x != null && y == null )
1715+ {
1716+ return 1 ;
1717+ }
15881718
1589- public int Compare ( JsonNode x , JsonNode y ) => string . CompareOrdinal ( x . ToString ( ) , y . ToString ( ) ) ;
1719+ return x . GetHashCode ( ) . CompareTo ( y . GetHashCode ( ) ) ;
1720+ }
15901721 }
15911722 }
15921723}
0 commit comments