basic abstraction first commit

This commit is contained in:
Mathias Beaulieu-Duncan 2025-10-06 14:02:18 -04:00
commit 6335c8e942
13 changed files with 247 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

View File

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/projectSettingsUpdater.xml
/contentModel.xml
/.idea.Svrnty.GeoManagement.iml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

58
CLAUDE.md Normal file
View File

@ -0,0 +1,58 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
**Svrnty.GeoManagement** is a .NET 8 library providing abstractions for geocoding and address management services. The solution follows a provider pattern to allow different geocoding service implementations.
## Solution Structure
The solution contains two projects:
- **Svrnty.GeoManagement.Abstractions**: Core abstractions and models for geocoding operations
- **Svrnty.GeoManagement.Tests**: xUnit test project
## Key Architecture Patterns
### Provider Pattern
The library uses the `IGeoManagementProvider` interface to abstract geocoding services. Implementations should provide:
- Forward geocoding (address to coordinates)
- Reverse geocoding (coordinates to address)
- Address normalization
### Address Model
The `Address` record in `Svrnty.GeoManagement.Abstractions/Models/Address.cs` is the central data structure. It:
- Implements `IAddress` interface
- Includes optional `GeoPoint` location data
- Provides formatted address output via `GetFormattedAddress()` method with three format types (Full, Compact, MultiLine)
- Has an `IsNormalized` flag to track address validation status
## Common Commands
### Build
```bash
dotnet build
```
### Run Tests
```bash
dotnet test
```
### Run Specific Test
```bash
dotnet test --filter "FullyQualifiedName~TestNamespace.TestClass.TestMethod"
```
### Restore Dependencies
```bash
dotnet restore
```
## Development Notes
- Target framework: .NET 8
- Nullable reference types are enabled
- The Abstractions project is designed to be provider-agnostic - don't add provider-specific dependencies
- When implementing `IGeoManagementProvider`, all methods support `CancellationToken` for async operations

View File

@ -0,0 +1,11 @@
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; }
}

View File

@ -0,0 +1,19 @@
using Svrnty.GeoManagement.Abstractions.Models;
namespace Svrnty.GeoManagement.Abstractions.Abstractions;
public interface IGeoManagementProvider
{
Task<GeoPoint?> GetGeoPointAsync(
Address address,
CancellationToken cancellationToken = default);
Task<Address?> ReverseGeocodeAsync(GeoPoint geoPoint,
CancellationToken cancellationToken = default);
Task<Address?> NormalizeAddressAsync(Address address,
CancellationToken cancellationToken = default);
Task<Address?> NormalizeAddressAsync(string address,
CancellationToken cancellationToken = default);
}

View File

@ -0,0 +1,61 @@
using Svrnty.GeoManagement.Abstractions.Abstractions;
namespace Svrnty.GeoManagement.Abstractions.Models;
public record GeoPoint(double Latitude, double 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 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}\n{Line1}\n{City}, {Subdivision} {PostalCode}\n{Country}";
}
}

View File

@ -0,0 +1,8 @@
namespace Svrnty.GeoManagement.Abstractions.Models;
public enum FormattedAddressType
{
Full,
Compact,
MultiLine
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
<PackageReference Include="xunit" Version="2.5.3"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
</ItemGroup>
<ItemGroup>
<Using Include="Xunit"/>
</ItemGroup>
</Project>

22
Svrnty.GeoManagement.sln Normal file
View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svrnty.GeoManagement.Tests", "Svrnty.GeoManagement.Tests\Svrnty.GeoManagement.Tests.csproj", "{C2DE2776-E457-49B0-A3E2-E31AFE8C922C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svrnty.GeoManagement.Abstractions", "Svrnty.GeoManagement.Abstractions\Svrnty.GeoManagement.Abstractions.csproj", "{FB10FC74-7B99-4B3C-A671-6DF451157C98}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C2DE2776-E457-49B0-A3E2-E31AFE8C922C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2DE2776-E457-49B0-A3E2-E31AFE8C922C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2DE2776-E457-49B0-A3E2-E31AFE8C922C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2DE2776-E457-49B0-A3E2-E31AFE8C922C}.Release|Any CPU.Build.0 = Release|Any CPU
{FB10FC74-7B99-4B3C-A671-6DF451157C98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB10FC74-7B99-4B3C-A671-6DF451157C98}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB10FC74-7B99-4B3C-A671-6DF451157C98}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FB10FC74-7B99-4B3C-A671-6DF451157C98}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal