Compare commits
2 Commits
35c09f0b3e
...
075a803f4f
Author | SHA1 | Date | |
---|---|---|---|
075a803f4f | |||
1c1b2877cf |
@ -2,10 +2,10 @@ namespace Svrnty.GeoManagement.Abstractions.Abstractions;
|
||||
|
||||
public interface IAddress
|
||||
{
|
||||
public string Line1 { get; }
|
||||
public string? Line2 { get; }
|
||||
public string City { get; }
|
||||
public string Subdivision { get; }
|
||||
public string PostalCode { get; }
|
||||
public string Country { get; }
|
||||
public string Line1 { get; set; }
|
||||
public string? Line2 { get; set; }
|
||||
public string City { get; set; }
|
||||
public string Subdivision { get; set; }
|
||||
public string PostalCode { get; set; }
|
||||
public string Country { get; set; }
|
||||
}
|
@ -2,60 +2,17 @@ using Svrnty.GeoManagement.Abstractions.Abstractions;
|
||||
|
||||
namespace Svrnty.GeoManagement.Abstractions.Models;
|
||||
|
||||
public record GeoPoint(double Latitude, double Longitude);
|
||||
public record GeoPoint(decimal Latitude, decimal Longitude);
|
||||
|
||||
public record Address(
|
||||
string Line1,
|
||||
string? Line2,
|
||||
string City,
|
||||
string Subdivision,
|
||||
string PostalCode,
|
||||
string Country,
|
||||
GeoPoint? Location,
|
||||
string? Note,
|
||||
bool IsNormalized = false
|
||||
) : IAddress
|
||||
public record Address(bool Normalized = false) : IAddress
|
||||
{
|
||||
public string GetFormattedAddress(
|
||||
FormattedAddressType formatType = FormattedAddressType.Full
|
||||
)
|
||||
{
|
||||
return formatType switch
|
||||
{
|
||||
FormattedAddressType.Full => FormatFullOneLine(),
|
||||
FormattedAddressType.Compact => FormatCompactOneLine(),
|
||||
FormattedAddressType.MultiLine => FormatMultiLine(),
|
||||
_ => FormatFullOneLine()
|
||||
};
|
||||
}
|
||||
|
||||
private string FormatFullOneLine()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Line2))
|
||||
{
|
||||
return $"{Line1}, {City}, {Subdivision} {PostalCode}, {Country}";
|
||||
}
|
||||
|
||||
return $"{Line2}, {Line1}, {City}, {Subdivision} {PostalCode}, {Country}";
|
||||
}
|
||||
|
||||
private string FormatCompactOneLine()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Line2))
|
||||
{
|
||||
return $"{Line1}, {City}, {Subdivision}";
|
||||
}
|
||||
|
||||
return $"{Line2}, {Line1}, {City}, {Subdivision}";
|
||||
}
|
||||
|
||||
private string FormatMultiLine()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Line2))
|
||||
{
|
||||
return $"{Line1}\n{City}, {Subdivision} {PostalCode}\n{Country}";
|
||||
}
|
||||
|
||||
return $"{Line2}, {Line1}\n{City}, {Subdivision} {PostalCode}\n{Country}";
|
||||
}
|
||||
public required string Line1 { get; set; }
|
||||
public string? Line2 { get; set; }
|
||||
public required string City { get; set; }
|
||||
public required string Subdivision { get; set; }
|
||||
public required string PostalCode { get; set; }
|
||||
public required string Country { get; set; }
|
||||
public GeoPoint? Location { get; set; }
|
||||
public string? Note { get; set; }
|
||||
public bool IsNormalized() => Normalized;
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using Svrnty.GeoManagement.Abstractions.Abstractions;
|
||||
using Svrnty.GeoManagement.Abstractions.Models;
|
||||
|
||||
namespace Svrnty.GeoManagement.Abstractions;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static void To(this IAddress address, IAddress toAddress)
|
||||
{
|
||||
toAddress.Line1 = address.Line1;
|
||||
toAddress.Line2 = address.Line2;
|
||||
toAddress.City = address.City;
|
||||
toAddress.PostalCode = address.PostalCode;
|
||||
toAddress.Country = address.Country;
|
||||
toAddress.Subdivision = address.Subdivision;
|
||||
}
|
||||
|
||||
public static void From(this IAddress address, IAddress fromAddress)
|
||||
{
|
||||
address.Line1 = fromAddress.Line1;
|
||||
address.Line2 = fromAddress.Line2;
|
||||
address.City = fromAddress.City;
|
||||
address.PostalCode = fromAddress.PostalCode;
|
||||
address.Country = fromAddress.Country;
|
||||
address.Subdivision = fromAddress.Subdivision;
|
||||
}
|
||||
|
||||
public static string GetFormattedAddress(this IAddress address, FormattedAddressType formatType = FormattedAddressType.Full)
|
||||
{
|
||||
return formatType switch
|
||||
{
|
||||
FormattedAddressType.Full => FormatFullOneLine(address),
|
||||
FormattedAddressType.Compact => FormatCompactOneLine(address),
|
||||
FormattedAddressType.MultiLine => FormatMultiLine(address),
|
||||
_ => FormatFullOneLine(address)
|
||||
};
|
||||
}
|
||||
|
||||
private static string FormatFullOneLine(IAddress address)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address.Line2))
|
||||
{
|
||||
return $"{address.Line1}, {address.City}, {address.Subdivision} {address.PostalCode}, {address.Country}";
|
||||
}
|
||||
|
||||
return $"{address.Line2}, {address.Line1}, {address.City}, {address.Subdivision} {address.PostalCode}, {address.Country}";
|
||||
}
|
||||
|
||||
private static string FormatCompactOneLine(IAddress address)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address.Line2))
|
||||
{
|
||||
return $"{address.Line1}, {address.City}, {address.Subdivision}";
|
||||
}
|
||||
|
||||
return $"{address.Line2}, {address.Line1}, {address.City}, {address.Subdivision}";
|
||||
}
|
||||
|
||||
private static string FormatMultiLine(IAddress address)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(address.Line2))
|
||||
{
|
||||
return $"{address.Line1}\n{address.City}, {address.Subdivision} {address.PostalCode}\n{address.Country}";
|
||||
}
|
||||
|
||||
return $"{address.Line2}, {address.Line1}\n{address.City}, {address.Subdivision} {address.PostalCode}\n{address.Country}";
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ using GoogleApi.Entities.Maps.Geocoding.Address.Request;
|
||||
using GoogleApi.Entities.Maps.Geocoding.Location.Request;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Svrnty.GeoManagement.Abstractions;
|
||||
using Svrnty.GeoManagement.Abstractions.Abstractions;
|
||||
using Svrnty.GeoManagement.Abstractions.Models;
|
||||
using Svrnty.GeoManagement.Google.Configuration;
|
||||
@ -91,7 +92,7 @@ public class GeoManagementGoogleProvider : IGeoManagementProvider
|
||||
var request = new LocationGeocodeRequest
|
||||
{
|
||||
Key = _options.ApiKey,
|
||||
Location = new GoogleApi.Entities.Common.Coordinate(geoPoint.Latitude, geoPoint.Longitude)
|
||||
Location = new GoogleApi.Entities.Common.Coordinate((double)geoPoint.Latitude, (double)geoPoint.Longitude)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_options.Language) &&
|
||||
|
@ -26,20 +26,20 @@ internal static class GoogleAddressMapper
|
||||
var country = GetComponentValue(components, "country") ?? string.Empty;
|
||||
|
||||
var location = googleResult.Geometry?.Location != null
|
||||
? new GeoPoint(googleResult.Geometry.Location.Latitude, googleResult.Geometry.Location.Longitude)
|
||||
? new GeoPoint((decimal)googleResult.Geometry.Location.Latitude, (decimal)googleResult.Geometry.Location.Longitude)
|
||||
: null;
|
||||
|
||||
return new Abstractions.Models.Address(
|
||||
Line1: line1,
|
||||
Line2: line2,
|
||||
City: city,
|
||||
Subdivision: subdivision,
|
||||
PostalCode: postalCode,
|
||||
Country: country,
|
||||
Location: location,
|
||||
Note: null,
|
||||
IsNormalized: true
|
||||
);
|
||||
return new Abstractions.Models.Address(Normalized: true)
|
||||
{
|
||||
Line1 = line1,
|
||||
Line2 = line2,
|
||||
City = city,
|
||||
Subdivision = subdivision,
|
||||
PostalCode = postalCode,
|
||||
Country = country,
|
||||
Location = location,
|
||||
Note = null
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildLine1(IEnumerable<AddressComponent> components)
|
||||
@ -79,8 +79,8 @@ internal static class GoogleAddressMapper
|
||||
return null;
|
||||
|
||||
return new GeoPoint(
|
||||
googleResult.Geometry.Location.Latitude,
|
||||
googleResult.Geometry.Location.Longitude
|
||||
(decimal)googleResult.Geometry.Location.Latitude,
|
||||
(decimal)googleResult.Geometry.Location.Longitude
|
||||
);
|
||||
}
|
||||
}
|
@ -24,12 +24,12 @@ public class AddressTestData
|
||||
|
||||
public class GeoPointTestData
|
||||
{
|
||||
public double Latitude { get; set; }
|
||||
public double Longitude { get; set; }
|
||||
public decimal Latitude { get; set; }
|
||||
public decimal Longitude { get; set; }
|
||||
}
|
||||
|
||||
public class CoordinateRange
|
||||
{
|
||||
public double Min { get; set; }
|
||||
public double Max { get; set; }
|
||||
public decimal Min { get; set; }
|
||||
public decimal Max { get; set; }
|
||||
}
|
||||
|
@ -54,15 +54,17 @@ public class GoogleProviderTests : IDisposable
|
||||
public async Task GetGeoPointAsync_WithValidAddress_ReturnsCoordinates()
|
||||
{
|
||||
// Arrange
|
||||
var address = new Address(
|
||||
Line1: _testData.ValidAddress.Line1,
|
||||
Line2: _testData.ValidAddress.Line2,
|
||||
City: _testData.ValidAddress.City,
|
||||
Subdivision: _testData.ValidAddress.Subdivision,
|
||||
PostalCode: _testData.ValidAddress.PostalCode,
|
||||
Country: _testData.ValidAddress.Country,
|
||||
Location: null,
|
||||
Note: null);
|
||||
var address = new Address
|
||||
{
|
||||
Line1 = _testData.ValidAddress.Line1,
|
||||
Line2 = _testData.ValidAddress.Line2,
|
||||
City = _testData.ValidAddress.City,
|
||||
Subdivision = _testData.ValidAddress.Subdivision,
|
||||
PostalCode = _testData.ValidAddress.PostalCode,
|
||||
Country = _testData.ValidAddress.Country,
|
||||
Location = null,
|
||||
Note = null
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _provider.GetGeoPointAsync(address);
|
||||
@ -89,7 +91,7 @@ public class GoogleProviderTests : IDisposable
|
||||
Assert.NotNull(result.Line1);
|
||||
Assert.NotNull(result.City);
|
||||
Assert.NotNull(result.Country);
|
||||
Assert.True(result.IsNormalized);
|
||||
Assert.True(result.IsNormalized());
|
||||
Assert.NotNull(result.Location);
|
||||
}
|
||||
|
||||
@ -97,22 +99,24 @@ public class GoogleProviderTests : IDisposable
|
||||
public async Task NormalizeAddressAsync_WithAddressObject_ReturnsNormalizedAddress()
|
||||
{
|
||||
// Arrange
|
||||
var address = new Address(
|
||||
Line1: _testData.NormalizeTestAddress.Line1,
|
||||
Line2: _testData.NormalizeTestAddress.Line2,
|
||||
City: _testData.NormalizeTestAddress.City,
|
||||
Subdivision: _testData.NormalizeTestAddress.Subdivision,
|
||||
PostalCode: _testData.NormalizeTestAddress.PostalCode,
|
||||
Country: _testData.NormalizeTestAddress.Country,
|
||||
Location: null,
|
||||
Note: null);
|
||||
var address = new Address
|
||||
{
|
||||
Line1 = _testData.NormalizeTestAddress.Line1,
|
||||
Line2 = _testData.NormalizeTestAddress.Line2,
|
||||
City = _testData.NormalizeTestAddress.City,
|
||||
Subdivision = _testData.NormalizeTestAddress.Subdivision,
|
||||
PostalCode = _testData.NormalizeTestAddress.PostalCode,
|
||||
Country = _testData.NormalizeTestAddress.Country,
|
||||
Location = null,
|
||||
Note = null
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _provider.NormalizeAddressAsync(address);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsNormalized);
|
||||
Assert.True(result.IsNormalized());
|
||||
Assert.NotNull(result.Location);
|
||||
Assert.NotNull(result.Line1);
|
||||
Assert.Contains("Amphitheatre", result.Line1, StringComparison.OrdinalIgnoreCase);
|
||||
@ -129,7 +133,7 @@ public class GoogleProviderTests : IDisposable
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.True(result.IsNormalized);
|
||||
Assert.True(result.IsNormalized());
|
||||
Assert.NotNull(result.Location);
|
||||
Assert.NotNull(result.Line1);
|
||||
Assert.Contains("Mountain View", result.City, StringComparison.OrdinalIgnoreCase);
|
||||
@ -139,15 +143,17 @@ public class GoogleProviderTests : IDisposable
|
||||
public async Task GetGeoPointAsync_WithInvalidAddress_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
var address = new Address(
|
||||
Line1: _testData.InvalidAddress.Line1,
|
||||
Line2: _testData.InvalidAddress.Line2,
|
||||
City: _testData.InvalidAddress.City,
|
||||
Subdivision: _testData.InvalidAddress.Subdivision,
|
||||
PostalCode: _testData.InvalidAddress.PostalCode,
|
||||
Country: _testData.InvalidAddress.Country,
|
||||
Location: null,
|
||||
Note: null);
|
||||
var address = new Address
|
||||
{
|
||||
Line1 = _testData.InvalidAddress.Line1,
|
||||
Line2 = _testData.InvalidAddress.Line2,
|
||||
City = _testData.InvalidAddress.City,
|
||||
Subdivision = _testData.InvalidAddress.Subdivision,
|
||||
PostalCode = _testData.InvalidAddress.PostalCode,
|
||||
Country = _testData.InvalidAddress.Country,
|
||||
Location = null,
|
||||
Note = null
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _provider.GetGeoPointAsync(address);
|
||||
@ -172,7 +178,7 @@ public class GoogleProviderTests : IDisposable
|
||||
// This test just verifies it doesn't crash
|
||||
if (result != null)
|
||||
{
|
||||
Assert.True(result.IsNormalized);
|
||||
Assert.True(result.IsNormalized());
|
||||
}
|
||||
}
|
||||
|
||||
|
2
Svrnty.GeoManagement.sln.DotSettings.user
Normal file
2
Svrnty.GeoManagement.sln.DotSettings.user
Normal file
@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FSourcesCache_003F728eee8ccad23b8fff516dba093eb71b49fb5ee8839f2118392e9747de4ebb_003FResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
Loading…
Reference in New Issue
Block a user