Skip to content

Commit

Permalink
First
Browse files Browse the repository at this point in the history
  • Loading branch information
StefH committed Apr 9, 2024
1 parent 9080f0c commit e658558
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -224,19 +224,6 @@ public static IQueryable Cast(this JArray source, string typeName)
#endregion Cast

#region Count
/// <summary>
/// Returns the number of elements in a sequence.
/// </summary>
/// <param name="source">The <see cref="JArray"/> that contains the elements to be counted.</param>
/// <returns>The number of elements in the input sequence.</returns>
public static int Count(this JArray source)
{
Check.NotNull(source);

var queryable = ToQueryable(source);
return queryable.Count();
}

/// <summary>
/// Returns the number of elements in a sequence.
/// </summary>
Expand Down Expand Up @@ -286,44 +273,61 @@ public static int Count(this JArray source, LambdaExpression lambda)
/// Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty.
/// </summary>
/// <param name="source">The <see cref="JArray"/> to return a default value for if empty.</param>
/// <returns>An <see cref="JArray"/> that contains default if source is empty; otherwise, source.</returns>
public static JArray DefaultIfEmpty(this JArray source)
/// <param name="defaultValue">The value to return if the sequence is empty.</param>
/// <returns>An <see cref="JArray"/> that contains defaultValue if source is empty; otherwise, source.</returns>
public static JArray DefaultIfEmpty(this JArray source, object? defaultValue)
{
Check.NotNull(source);

var queryable = ToQueryable(source);
return ToJArray(queryable.DefaultIfEmpty);
return ToJArray(() => queryable.DefaultIfEmpty(defaultValue));
}
#endregion

#region First
/// <summary>
/// Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty.
/// Returns the first element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="source">The <see cref="JArray"/> to return a default value for if empty.</param>
/// <param name="defaultValue">The value to return if the sequence is empty.</param>
/// <returns>An <see cref="JArray"/> that contains defaultValue if source is empty; otherwise, source.</returns>
public static JArray DefaultIfEmpty(this JArray source, object? defaultValue)
/// <param name="source">The <see cref="JArray"/> to return the first element of.</param>
/// <param name="config">The <see cref="NewtonsoftJsonParsingConfig"/>.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
/// <returns>The first element in source that passes the test in predicate.</returns>
public static JToken First(this JArray source, NewtonsoftJsonParsingConfig config, string predicate, params object?[] args)
{
Check.NotNull(source);
Check.NotNull(config);

var queryable = ToQueryable(source);
return ToJArray(() => queryable.DefaultIfEmpty(defaultValue));
var queryable = ToQueryable(source, config);
return ToJToken(queryable.First(config, predicate, args));
}
#endregion

#region Distinct
/// <summary>
/// Returns distinct elements from a sequence by using the default equality comparer to compare values.
/// Returns the first element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="source">The sequence to remove duplicate elements from.</param>
/// <returns>An <see cref="JArray"/> that contains distinct elements from the source sequence.</returns>
public static JArray Distinct(this JArray source)
/// <param name="source">The <see cref="JArray"/> to return the first element of.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
/// <returns>The first element in source that passes the test in predicate.</returns>
public static JToken First(this JArray source, string predicate, params object?[] args)
{
return First(source, NewtonsoftJsonParsingConfig.Default, predicate, args);
}

/// <summary>
/// Returns the first element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="source">The <see cref="JArray"/> to return the first element of.</param>
/// <param name="lambda">A cached Lambda Expression.</param>
/// <returns>The first element in source that passes the test in predicate.</returns>
public static JToken First(this JArray source, LambdaExpression lambda)
{
Check.NotNull(source);

var queryable = ToQueryable(source);
return ToJArray(queryable.Distinct);
return ToJToken(queryable.First(lambda));
}
#endregion Distinct
#endregion First

#region Select
/// <summary>
Expand Down Expand Up @@ -399,6 +403,16 @@ public static JArray Where(this JArray source, NewtonsoftJsonParsingConfig confi
}
#endregion Where

#region Private Methods
private static JToken ToJToken(object value)
{
if (value is JToken jToken)
{
return jToken;
}

return JToken.FromObject(value);
}
private static JArray ToJArray(Func<IQueryable> func)
{
var array = new JArray();
Expand All @@ -415,4 +429,5 @@ private static IQueryable ToQueryable(JArray source, NewtonsoftJsonParsingConfig
{
return source.ToDynamicJsonClassArray(config?.DynamicJsonClassOptions).AsQueryable();
}
#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Description>TODO</Description>
<PackageTags>system;linq;dynamic;core;dotnet;json</PackageTags>
<ProjectGuid>{8C5851B8-5C47-4229-AB55-D4252703598E}</ProjectGuid>
<TargetFrameworks>net40;net45;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net45;net452;net46;netstandard1.3;netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
<Version>1.3.$(PatchVersion)</Version>
</PropertyGroup>

Expand All @@ -22,7 +22,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.5.0" />
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.5.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

<ItemGroup>
<PackageReference Include="JsonConverter.System.Text.Json" Version="0.5.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,64 @@ public static JsonDocument Distinct(this JsonDocument source)
}
#endregion Distinct

#region First
/// <summary>
/// Returns the first element of a sequence.
/// </summary>
/// <param name="source">The <see cref="JsonDocument"/> to return the first element of.</param>
/// <returns>The first element in source.</returns>
public static JsonElement First(this JsonDocument source)
{
Check.NotNull(source);

var queryable = ToQueryable(source);
return ToJsonElement(queryable.First());
}

/// <summary>
/// Returns the first element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="source">The <see cref="JsonDocument"/> to return the first element of.</param>
/// <param name="config">The <see cref="SystemTextJsonParsingConfig"/>.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
/// <returns>The first element in source that passes the test in predicate.</returns>
public static JsonElement First(this JsonDocument source, SystemTextJsonParsingConfig config, string predicate, params object?[] args)
{
Check.NotNull(source);
Check.NotNull(config);

var queryable = ToQueryable(source, config);
return ToJsonElement(queryable.First(config, predicate, args));
}

/// <summary>
/// Returns the first element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="source">The <see cref="JsonDocument"/> to return the first element of.</param>
/// <param name="predicate">A function to test each element for a condition.</param>
/// <param name="args">An object array that contains zero or more objects to insert into the predicate as parameters. Similar to the way String.Format formats strings.</param>
/// <returns>The first element in source that passes the test in predicate.</returns>
public static JsonElement First(this JsonDocument source, string predicate, params object?[] args)
{
return First(source, SystemTextJsonParsingConfig.Default, predicate, args);
}

/// <summary>
/// Returns the first element of a sequence that satisfies a specified condition.
/// </summary>
/// <param name="source">The <see cref="JsonDocument"/> to return the first element of.</param>
/// <param name="lambda">A cached Lambda Expression.</param>
/// <returns>The first element in source that passes the test in predicate.</returns>
public static JsonElement First(this JsonDocument source, LambdaExpression lambda)
{
Check.NotNull(source);

var queryable = ToQueryable(source);
return ToJsonElement(queryable.First(lambda));
}
#endregion First

#region Select
/// <summary>
/// Projects each element of a sequence into a new form.
Expand Down Expand Up @@ -391,13 +449,22 @@ public static JsonDocument Where(this JsonDocument source, SystemTextJsonParsing
#endregion Where

#region Private Methods
private static JsonElement ToJsonElement(object value)
{
if (value is JsonElement jsonElement)
{
return jsonElement;
}

return JsonElementUtils.FromObject(value);
}

private static JsonDocument ToJsonDocumentArray(Func<IQueryable> func)
{
var array = new List<object>();
foreach (var dynamicElement in func())
{
var element = dynamicElement is DynamicClass dynamicClass ? JsonElementUtils.FromObject(dynamicClass) : dynamicElement;
array.Add(element);
array.Add(ToJsonElement(dynamicElement));
}

return JsonDocumentUtils.FromObject(array);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ public void Distinct()
result.Should().HaveCount(2);
}

[Fact]
public void First()
{
// Act + Assert 1
_source.First().Should().NotBeNull();

((string?)_source.First("Age > 30")["Name"]).Should().Be("Doe");
}

[Fact]
public void Select()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ public void Distinct()
result.RootElement.EnumerateArray().Should().HaveCount(2);
}

[Fact]
public void First()
{
// Act + Assert 1
_source.First().GetRawText().Should().BeEquivalentTo(JsonDocument.Parse(@"{""Name"":""John"",""Age"":30}").RootElement.GetRawText());

_source.First("Age > 30").GetRawText().Should().BeEquivalentTo(JsonDocument.Parse(@"{""Name"":""Doe"",""Age"":40}").RootElement.GetRawText());
}

[Fact]
public void Select()
{
Expand Down

0 comments on commit e658558

Please sign in to comment.