Skip to content

Commit

Permalink
feat: Added IsMeasurement option to Column attribute, and additional …
Browse files Browse the repository at this point in the history
…serialization/deserialization logic
  • Loading branch information
Chris Cameron committed Sep 23, 2021
1 parent 09986be commit 811cc19
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 6 deletions.
4 changes: 4 additions & 0 deletions Client.Core/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace InfluxDB.Client.Core
/// <summary>
/// The annotation is used for mapping POCO class into line protocol.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class Measurement : Attribute
{
public string Name { get; }
Expand All @@ -18,10 +19,13 @@ public Measurement(string name)
/// <summary>
/// The annotation is used to customize bidirectional mapping between POCO and Flux query result or Line Protocol.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class Column : Attribute
{
public string Name { get; }

public bool IsMeasurement { get; set; }

public bool IsTag { get; set; }

public bool IsTimestamp { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion Client.Core/Flux/Internal/AttributesCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public PropertyInfo[] GetProperties(Type type)
}

/// <summary>
/// Get Mapping attribute for specified propery.
/// Get Mapping attribute for specified property.
/// </summary>
/// <param name="property">property of DomainObject</param>
/// <returns>Property Attribute</returns>
Expand Down
4 changes: 4 additions & 0 deletions Client.Core/Flux/Internal/FluxResultMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ internal object ToPoco(FluxRecord record, Type type)
{
var attribute = _attributesCache.GetAttribute(property);

if (attribute != null && attribute.IsMeasurement)
{
SetFieldValue(poco, property, record.GetMeasurement());
}
if (attribute != null && attribute.IsTimestamp)
{
SetFieldValue(poco, property, record.GetTime());
Expand Down
6 changes: 6 additions & 0 deletions Client.Linq/IMemberNameResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public interface IMemberNameResolver

public enum MemberType
{
Measurement,
Tag,
Field,
Timestamp,
Expand All @@ -52,6 +53,11 @@ public MemberType ResolveMemberType(MemberInfo memberInfo)

if (attribute != null)
{
if (attribute.IsMeasurement)
{
return MemberType.Measurement;
}

if (attribute.IsTag)
{
return MemberType.Tag;
Expand Down
59 changes: 58 additions & 1 deletion Client.Test/MeasurementMapperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,36 @@ public void HeavyLoad()

Assert.LessOrEqual(ts.Seconds, 10, $"Elapsed time: {elapsedTime}");
}


[Test]
public void MeasurementProperty()
{
var poco = new MeasurementPropertyPoco
{
Measurement = "poco",
Tag = "tag val",
Value = 15.444,
ValueWithoutDefaultName = 20,
ValueWithEmptyName = 25d,
Timestamp = TimeSpan.FromDays(10)
};

var lineProtocol = _mapper.ToPoint(poco, WritePrecision.S).ToLineProtocol();

Assert.AreEqual("poco,tag=tag\\ val value=15.444,ValueWithEmptyName=25,ValueWithoutDefaultName=20i 864000", lineProtocol);
}

[Test]
public void MeasurementPropertyValidation()
{
var poco = new BadMeasurementAttributesPoco
{
Measurement = "poco"
};

Assert.Throws<InvalidOperationException>(() => _mapper.ToPoint(poco, WritePrecision.S));
}

private class MyClass
{
public override string ToString()
Expand All @@ -118,5 +147,33 @@ private class Poco
[Column(IsTimestamp = true)]
public Object Timestamp { get; set; }
}

private class MeasurementPropertyPoco
{
[Column(IsMeasurement = true)]
public string Measurement { get; set; }

[Column("tag", IsTag = true)]
public string Tag { get; set; }

[Column("value")]
public Object Value { get; set; }

[Column]
public int? ValueWithoutDefaultName { get; set; }

[Column("")]
public Double? ValueWithEmptyName { get; set; }

[Column(IsTimestamp = true)]
public Object Timestamp { get; set; }
}

[Measurement("poco")]
private class BadMeasurementAttributesPoco
{
[Column(IsMeasurement = true)]
public string Measurement { get; set; }
}
}
}
3 changes: 3 additions & 0 deletions Client.Test/QueryApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public async Task GenericAndTypeofCalls()
Assert.AreEqual(13.00, measurements[1].Value);
Assert.IsAssignableFrom<SyncPoco>(measurementsTypeof[0]);
var cast = measurementsTypeof.Cast<SyncPoco>().ToList();
Assert.AreEqual(measurements[0].Measurement, cast[0].Measurement);
Assert.AreEqual(measurements[0].Timestamp, cast[0].Timestamp);
Assert.AreEqual(12.25, cast[0].Value);
Assert.AreEqual(13.00, cast[1].Value);
Expand All @@ -88,6 +89,8 @@ public async Task GenericAndTypeofCalls()

private class SyncPoco
{
[Column(IsMeasurement = true)] public string Measurement { get; set; }

[Column("id", IsTag = true)] public string Tag { get; set; }

[Column("_value")] public double Value { get; set; }
Expand Down
20 changes: 16 additions & 4 deletions Client/Internal/MeasurementMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,30 @@ internal PointData ToPoint<TM>(TM measurement, WritePrecision precision)

var measurementType = measurement.GetType();
CacheMeasurementClass(measurementType);

var measurementAttribute = (Measurement) measurementType.GetCustomAttribute(typeof(Measurement));
if (measurementAttribute == null)
var measurementColumn = CACHE[measurementType.Name].SingleOrDefault(p => p.Column.IsMeasurement);

if ((measurementAttribute == null) ^ (measurementColumn == null) == false)
{
throw new InvalidOperationException(
$"Measurement {measurement} does not have a {typeof(Measurement)} attribute.");
$"Unable to determine Measurement for {measurement}. Does it have a {typeof(Measurement)} or IsMessage {typeof(Column)} attribute?");
}

var point = PointData.Measurement(measurementAttribute.Name);
string measurementName =
measurementAttribute == null
? (string)measurementColumn.Property.GetValue(measurement)
: measurementAttribute.Name;

var point = PointData.Measurement(measurementName);

foreach (var propertyInfo in CACHE[measurementType.Name])
{
if (propertyInfo.Column.IsMeasurement)
{
continue;
}

var value = propertyInfo.Property.GetValue(measurement);
if (value == null)
{
Expand Down

0 comments on commit 811cc19

Please sign in to comment.