mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-02 13:13:21 +00:00
210 lines
8 KiB
C#
210 lines
8 KiB
C#
using Data.SeaHavenIndustries;
|
|
using Data.SeaHavenIndustries.Enums;
|
|
using Microsoft.Data.Sqlite;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using SeaHaven.DataServices.Helpers;
|
|
using SeaHaven.DataServices.Implementation;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
|
|
namespace SeaHavenIndustries.Tests;
|
|
|
|
public sealed class WorkOrderServiceRegistryKeywordSearchRelationalTests
|
|
{
|
|
[Fact]
|
|
public async Task Search_MatchesCurrentAndHistoricalServiceLabelsAndPreservesExistingAliases()
|
|
{
|
|
await using var connection = new SqliteConnection("Data Source=:memory:;Foreign Keys=True");
|
|
await connection.OpenAsync();
|
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
|
.UseSqlite(connection)
|
|
.Options;
|
|
|
|
await using var context = new SqliteSearchTestDbContext(options);
|
|
await context.Database.EnsureCreatedAsync();
|
|
|
|
context.Services.AddRange(
|
|
new Service
|
|
{
|
|
Id = 10,
|
|
Name = "Chiller Maintenance Original",
|
|
NormalizedName = "CHILLER MAINTENANCE ORIGINAL",
|
|
Trade = "HVAC",
|
|
IconKey = "hvac",
|
|
IsActive = true
|
|
},
|
|
new Service
|
|
{
|
|
Id = 20,
|
|
Name = "Roof Maintenance Current",
|
|
NormalizedName = "ROOF MAINTENANCE CURRENT",
|
|
Trade = "Roofing",
|
|
IconKey = "roofing",
|
|
IsActive = true
|
|
},
|
|
new Service
|
|
{
|
|
Id = 30,
|
|
Name = "Pump Service Current",
|
|
NormalizedName = "PUMP SERVICE CURRENT",
|
|
Trade = "Plumbing",
|
|
IconKey = "plumbing",
|
|
IsActive = false
|
|
});
|
|
context.Vendors.Add(new Vendor
|
|
{
|
|
Id = 40,
|
|
CompanyName = "Acme Vendor Group",
|
|
ContactName = "Morgan Technician"
|
|
});
|
|
context.Dispatches.Add(new Dispatch { Id = 50, VendorId = 40, Status = "Sent" });
|
|
context.workOrders.AddRange(
|
|
new WorkOrder
|
|
{
|
|
Id = 1,
|
|
ServiceId = 10,
|
|
ServiceNameSnapshot = "Legacy Chiller Label",
|
|
Trade = "HVAC",
|
|
Problem = "Cooling noise",
|
|
LifecycleStatus = LifecycleStatus.Scheduled,
|
|
WorkOrderType = WorkOrderType.PM,
|
|
ScheduledDate = new DateTime(2026, 9, 15),
|
|
PrimaryDispatchId = 50,
|
|
TechnicianAssigned = true
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 2,
|
|
ServiceId = 20,
|
|
ServiceNameSnapshot = "Frozen Roof Label",
|
|
Trade = "Roofing",
|
|
Problem = "Roof leak",
|
|
LifecycleStatus = LifecycleStatus.Completed,
|
|
WorkOrderType = WorkOrderType.PM,
|
|
ScheduledDate = new DateTime(2026, 9, 15)
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 3,
|
|
ServiceId = 30,
|
|
ServiceNameSnapshot = "Historical Pump Label",
|
|
Trade = "Plumbing",
|
|
Problem = "Pump noise",
|
|
LifecycleStatus = LifecycleStatus.Scheduled,
|
|
WorkOrderType = WorkOrderType.PM,
|
|
ScheduledDate = new DateTime(2026, 9, 15)
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 4,
|
|
Trade = "Legacy Boiler Service",
|
|
Problem = "Oil leak",
|
|
LifecycleStatus = LifecycleStatus.Scheduled,
|
|
WorkOrderType = WorkOrderType.Reactive,
|
|
ScheduledDate = new DateTime(2026, 9, 15)
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 5,
|
|
Trade = "Unlinked vendor WO",
|
|
LifecycleStatus = LifecycleStatus.Scheduled,
|
|
WorkOrderType = WorkOrderType.Reactive,
|
|
ScheduledDate = new DateTime(2026, 9, 15),
|
|
PrimaryDispatchId = 50,
|
|
TechnicianAssigned = false
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var renamedService = await context.Services.SingleAsync(service => service.Id == 10);
|
|
renamedService.Name = "Northstar Chiller Service";
|
|
renamedService.NormalizedName = "NORTHSTAR CHILLER SERVICE";
|
|
await context.SaveChangesAsync();
|
|
|
|
async Task<int[]> SearchIds(string search)
|
|
=> await WorkOrderBoardSearchFilter
|
|
.Apply(context.workOrders.AsNoTracking(), search)
|
|
.Select(workOrder => workOrder.Id)
|
|
.OrderBy(id => id)
|
|
.ToArrayAsync();
|
|
|
|
Assert.Equal(new[] { 1 }, await SearchIds("Northstar Chiller Service"));
|
|
Assert.Equal(new[] { 1 }, await SearchIds("Legacy Chiller Label"));
|
|
Assert.Equal(new[] { 2 }, await SearchIds("Frozen Roof Label"));
|
|
Assert.Equal(new[] { 2 }, await SearchIds("Roof Maintenance Current"));
|
|
Assert.Equal(new[] { 3 }, await SearchIds("Historical Pump Label"));
|
|
Assert.Equal(new[] { 3 }, await SearchIds("Pump Service Current"));
|
|
Assert.Equal(new[] { 4 }, await SearchIds("Legacy Boiler Service"));
|
|
Assert.Equal(new[] { 4 }, await SearchIds("Oil leak"));
|
|
Assert.Equal(new[] { 1, 5 }, await SearchIds("Acme Vendor Group"));
|
|
Assert.Equal(new[] { 1 }, await SearchIds("Morgan Technician"));
|
|
|
|
var advancedSearch = new WorkOrderAdvancedSearchDataService(context);
|
|
var matchingFacet = await advancedSearch.SearchAsync(CreateQuery(
|
|
search: "Northstar Chiller Service",
|
|
pmTypes: new[] { "Northstar Chiller Service" }));
|
|
Assert.Equal(new[] { 1 }, matchingFacet.Rows.Select(row => row.Id));
|
|
Assert.Equal("Northstar Chiller Service", Assert.Single(matchingFacet.Rows).Trade);
|
|
|
|
var conflictingFacet = await advancedSearch.SearchAsync(CreateQuery(
|
|
search: "Northstar Chiller Service",
|
|
pmTypes: new[] { "Roof Maintenance Current" }));
|
|
Assert.Empty(conflictingFacet.Rows);
|
|
Assert.Equal(0, conflictingFacet.TotalCount);
|
|
}
|
|
|
|
private static WorkOrderAdvancedSearchQuery CreateQuery(string search, IReadOnlyList<string>? pmTypes = null)
|
|
=> new(
|
|
Search: search,
|
|
DateFrom: new DateOnly(2026, 9, 1),
|
|
DateTo: new DateOnly(2026, 9, 30),
|
|
UnscheduledOnly: false,
|
|
Sites: null,
|
|
Regions: null,
|
|
Types: null,
|
|
Overdue: false,
|
|
Dispatchers: null,
|
|
Statuses: null,
|
|
PmTypes: pmTypes,
|
|
VendorIds: null,
|
|
DocStatuses: null,
|
|
Severities: null,
|
|
Rescheduled: false,
|
|
CarriedOver: false,
|
|
AddOn: false,
|
|
AvetaOnly: false,
|
|
FlagColors: null,
|
|
InternalOnly: false,
|
|
HasUplift: false,
|
|
UpliftStatuses: null,
|
|
MyWorkOrders: false,
|
|
CurrentUserId: null,
|
|
Page: 0,
|
|
PageSize: 100,
|
|
SortBy: "scheduledDate",
|
|
SortDir: "asc");
|
|
|
|
private sealed class SqliteSearchTestDbContext : ApplicationDbContext
|
|
{
|
|
public SqliteSearchTestDbContext(DbContextOptions<ApplicationDbContext> options)
|
|
: base(options)
|
|
{
|
|
}
|
|
|
|
protected override void OnModelCreating(ModelBuilder builder)
|
|
{
|
|
base.OnModelCreating(builder);
|
|
|
|
foreach (var index in builder.Model.GetEntityTypes().SelectMany(entity => entity.GetIndexes()))
|
|
{
|
|
if (index.GetFilter() != null)
|
|
index.SetFilter(null);
|
|
}
|
|
|
|
foreach (var entityType in new[] { typeof(WorkOrder), typeof(Dispatch) })
|
|
{
|
|
var property = builder.Entity(entityType).Property("RowVersion").Metadata;
|
|
property.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.Never;
|
|
property.IsConcurrencyToken = false;
|
|
}
|
|
}
|
|
}
|
|
}
|