92 lines
3.1 KiB
C#
92 lines
3.1 KiB
C#
using LocationsApi.Models;
|
|
using MongoDB.Driver;
|
|
|
|
namespace LocationsApi.Services;
|
|
|
|
public class LocationService
|
|
{
|
|
private readonly IMongoCollection<Location> _locations;
|
|
|
|
public LocationService(IConfiguration cfg)
|
|
{
|
|
var connectionString = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017";
|
|
var databaseName = cfg["MongoDB:DatabaseName"] ?? "territory-autobattler";
|
|
var client = new MongoClient(connectionString);
|
|
var database = client.GetDatabase(databaseName);
|
|
_locations = database.GetCollection<Location>("Locations");
|
|
|
|
var coordinateIndex = Builders<Location>.IndexKeys
|
|
.Ascending(x => x.Q)
|
|
.Ascending(x => x.R);
|
|
_locations.Indexes.CreateOne(new CreateIndexModel<Location>(
|
|
coordinateIndex,
|
|
new CreateIndexOptions { Unique = true }));
|
|
}
|
|
|
|
public Task<List<Location>> GetAllAsync() =>
|
|
_locations.Find(FilterDefinition<Location>.Empty)
|
|
.SortBy(x => x.Q)
|
|
.ThenBy(x => x.R)
|
|
.ToListAsync();
|
|
|
|
public Task<List<Location>> GetRangeAsync(int minQ, int maxQ, int minR, int maxR) =>
|
|
_locations.Find(x => x.Q >= minQ && x.Q <= maxQ && x.R >= minR && x.R <= maxR)
|
|
.SortBy(x => x.Q)
|
|
.ThenBy(x => x.R)
|
|
.ToListAsync();
|
|
|
|
public async Task<Location?> GetAsync(int q, int r) =>
|
|
await _locations.Find(x => x.Q == q && x.R == r).FirstOrDefaultAsync();
|
|
|
|
public async Task<Location> UpsertAsync(UpsertLocationRequest request, string? ownerUsername = null)
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
var update = Builders<Location>.Update
|
|
.SetOnInsert(x => x.CreatedAtUtc, now)
|
|
.Set(x => x.Terrain, NormalizeTerrain(request.Terrain))
|
|
.Set(x => x.Label, request.Label)
|
|
.Set(x => x.Level, Math.Max(1, request.Level))
|
|
.Set(x => x.UpdatedAtUtc, now);
|
|
|
|
if (!string.IsNullOrWhiteSpace(ownerUsername))
|
|
{
|
|
update = update.Set(x => x.OwnerUsername, ownerUsername);
|
|
}
|
|
|
|
var options = new FindOneAndUpdateOptions<Location>
|
|
{
|
|
IsUpsert = true,
|
|
ReturnDocument = ReturnDocument.After
|
|
};
|
|
|
|
return await _locations.FindOneAndUpdateAsync(
|
|
x => x.Q == request.Q && x.R == request.R,
|
|
update,
|
|
options);
|
|
}
|
|
|
|
public async Task<Location> ClaimAsync(int q, int r, string username)
|
|
{
|
|
var existing = await GetAsync(q, r);
|
|
if (existing is not null)
|
|
{
|
|
existing.OwnerUsername = username;
|
|
existing.UpdatedAtUtc = DateTime.UtcNow;
|
|
await _locations.ReplaceOneAsync(x => x.Id == existing.Id, existing);
|
|
return existing;
|
|
}
|
|
|
|
return await UpsertAsync(new UpsertLocationRequest { Q = q, R = r, Terrain = "Field" }, username);
|
|
}
|
|
|
|
private static string NormalizeTerrain(string terrain)
|
|
{
|
|
var trimmed = terrain.Trim();
|
|
return trimmed switch
|
|
{
|
|
"Command" or "Field" or "Forest" or "Ore" or "Highland" => trimmed,
|
|
_ => "Field"
|
|
};
|
|
}
|
|
}
|