Skip to content

Commit

Permalink
Implement IParsable<T> for url parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
flobernd committed Feb 10, 2025
1 parent 4e18b84 commit 55b8b2e
Show file tree
Hide file tree
Showing 29 changed files with 985 additions and 73 deletions.
7 changes: 2 additions & 5 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
{
"sdk": {
"version": "8.0.400",
"version": "9.0.100",
"rollForward": "latestFeature",
"allowPrerelease": false
},
"version": "8.8.0-alpha.1",
"doc_current": "main",
"doc_branch": "main"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -15,7 +17,13 @@ namespace Elastic.Clients.Elasticsearch;
/// Represents a duration value.
/// </summary>
[JsonConverter(typeof(DurationConverter))]
public sealed class Duration : IComparable<Duration>, IEquatable<Duration>, IUrlParameter
public sealed class Duration :
IComparable<Duration>,
IEquatable<Duration>,
IUrlParameter
#if NET7_0_OR_GREATER
, IParsable<Duration>
#endif
{
private const double MicrosecondsInATick = 0.1; // 10 ticks = 1 microsecond
private const double MillisecondsInADay = MillisecondsInAnHour * 24;
Expand Down Expand Up @@ -390,6 +398,35 @@ private static string ExponentFormat(double d)
var exponent = (int)((bits >> 52) & 0x7ffL);
return new string('#', Math.Max(2, exponent));
}

#region IParsable

public static Duration Parse(string s, IFormatProvider? provider) =>
TryParse(s, provider, out var result) ? result : throw new FormatException();

public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider,
[NotNullWhen(true)] out Duration? result)
{
if (s is null)
{
result = null;
return false;
}

try
{
result = new Duration(s);
}
catch
{
result = null;
return false;
}

return true;
}

#endregion IParsable
}

internal sealed class DurationConverter : JsonConverter<Duration>
Expand Down
42 changes: 42 additions & 0 deletions src/Elastic.Clients.Elasticsearch/_Shared/Core/EnumValueParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace Elastic.Clients.Elasticsearch;

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

internal static class EnumValueParser<T>
where T : struct, Enum
{
private static readonly Dictionary<string, T> ValueMap = new(StringComparer.OrdinalIgnoreCase);

static EnumValueParser()
{
foreach (var value in Enum.GetValues<T>())
{
var name = value.ToString();
ValueMap[name] = value;

var field = typeof(T).GetField(name);
var attribute = (EnumMemberAttribute?)Attribute.GetCustomAttribute(field!, typeof(EnumMemberAttribute));
if (attribute?.Value is not null)
{
ValueMap[attribute.Value] = value;
}
}
}

public static bool TryParse(string input, out T result)
{
return ValueMap.TryGetValue(input, out result);
}

public static T Parse(string input)
{
if (ValueMap.TryGetValue(input, out var result))
{
return result;
}

throw new ArgumentException($"Unknown member '{input}' for enum '{typeof(T).Name}'.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ public abstract class Descriptor<TDescriptor> : Descriptor
protected TDescriptor Self => _self;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected TDescriptor Assign<TValue>(TValue value, Action<TDescriptor, TValue> assign) => FluentAssign.Assign(_self, value, assign);
protected TDescriptor Assign<TValue>(TValue value, Action<TDescriptor, TValue> assign)
{
assign(_self, value);
return _self;
}
}

public abstract class SerializableDescriptor<TDescriptor> : Descriptor<TDescriptor>, ISelfSerializable
Expand Down
19 changes: 0 additions & 19 deletions src/Elastic.Clients.Elasticsearch/_Shared/Core/Fluent/Fluent.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ namespace Elastic.Clients.Elasticsearch;
public sealed class Field :
IEquatable<Field>,
IUrlParameter
#if NET7_0_OR_GREATER
, IParsable<Field>
#endif
{
private readonly object _comparisonValue;
private readonly Type? _type;
Expand Down Expand Up @@ -197,6 +200,26 @@ public override int GetHashCode()

#endregion Equality

#region IParsable

public static Field Parse(string s, IFormatProvider? provider) =>
TryParse(s, provider, out var result) ? result : throw new FormatException();

public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider,
[NotNullWhen(true)] out Field? result)
{
if (s is null)
{
result = null;
return false;
}

result = new Field(s);
return true;
}

#endregion IParsable

#region IUrlParameter

string IUrlParameter.GetString(ITransportConfiguration settings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
Expand All @@ -19,6 +20,9 @@ public sealed class Fields :
IEquatable<Fields>,
IEnumerable<Field>,
IUrlParameter
#if NET7_0_OR_GREATER
, IParsable<Fields>
#endif
{
internal readonly List<Field> ListOfFields;

Expand Down Expand Up @@ -183,6 +187,44 @@ public override bool Equals(object? obj) =>

#endregion IEnumerable

#region IParsable

public static Fields Parse(string s, IFormatProvider? provider) =>
TryParse(s, provider, out var result) ? result : throw new FormatException();

public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider,
[NotNullWhen(true)] out Fields? result)
{
if (s is null)
{
result = null;
return false;
}

if (s.IsNullOrEmptyCommaSeparatedList(out var list))
{
result = new Fields();
return true;
}

var fields = new List<Field>();
foreach (var item in list)
{
if (!Field.TryParse(item, provider, out var field))
{
result = null;
return false;
}

fields.Add(field);
}

result = new Fields(fields);
return true;
}

#endregion IParsable

#region IUrlParameter

string IUrlParameter.GetString(ITransportConfiguration? settings)
Expand Down
33 changes: 32 additions & 1 deletion src/Elastic.Clients.Elasticsearch/_Shared/Core/Infer/Id/Id.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

using Elastic.Transport;

namespace Elastic.Clients.Elasticsearch;

[DebuggerDisplay("{DebugDisplay,nq}")]
[JsonConverter(typeof(IdConverter))]
public class Id : IEquatable<Id>, IUrlParameter
public class Id :
IEquatable<Id>,
IUrlParameter
#if NET7_0_OR_GREATER
, IParsable<Id>
#endif
{
public Id(string id)
{
Expand Down Expand Up @@ -81,12 +88,16 @@ public override bool Equals(object obj)
{
case Id r:
return Equals(r);

case string s:
return Equals(s);

case int l:
return Equals(l);

case long l:
return Equals(l);

case Guid g:
return Equals(g);
}
Expand All @@ -108,4 +119,24 @@ public override int GetHashCode()
public static bool operator ==(Id left, Id right) => Equals(left, right);

public static bool operator !=(Id left, Id right) => !Equals(left, right);

#region IParsable

public static Id Parse(string s, IFormatProvider? provider) =>
TryParse(s, provider, out var result) ? result : throw new FormatException();

public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider,
[NotNullWhen(true)] out Id? result)
{
if (s is null)
{
result = null;
return false;
}

result = new Id(s);
return true;
}

#endregion IParsable
}
Loading

0 comments on commit 55b8b2e

Please sign in to comment.