mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-02-04 05:35:44 +00:00
Filtering of collection by item property tests added
This commit is contained in:
@@ -2539,5 +2539,504 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains("rz-grid-filter", component.Markup);
|
||||
}
|
||||
|
||||
// Property/FilterProperty tests for filtering collection items
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithSimpleMode()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Name = "Product1", Tags = new[] { new { Label = "new", Priority = 1 } } },
|
||||
new { Id = 2, Name = "Product2", Tags = new[] { new { Label = "sale", Priority = 2 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Name");
|
||||
builder.AddAttribute(2, "Title", "Name");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Simple);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-cell-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithSimpleWithMenuMode()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Name = "Order1", Items = new[] { new { Product = "A", Quantity = 5 } } },
|
||||
new { Id = 2, Name = "Order2", Items = new[] { new { Product = "B", Quantity = 10 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Name");
|
||||
builder.AddAttribute(2, "Title", "Name");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-filter-button", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithAdvancedMode()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Name = "Customer1", Orders = new[] { new { OrderId = "A1", Total = 100 } } },
|
||||
new { Id = 2, Name = "Customer2", Orders = new[] { new { OrderId = "B1", Total = 200 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Name");
|
||||
builder.AddAttribute(2, "Title", "Name");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Advanced);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-grid-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_StringProperty_WithEquals()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "important", Value = 10 } } },
|
||||
new { Id = 2, Tags = new[] { new { Name = "normal", Value = 20 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("Equals", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_NumericProperty_WithComparison()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Quantity = 5, Price = 100 } } },
|
||||
new { Id = 2, Items = new[] { new { Quantity = 10, Price = 200 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("Greater than", component.Markup);
|
||||
Assert.Contains("Less than", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithStartsWithOperator()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Files = new[] { new { Name = "file.txt", Size = 100 } } },
|
||||
new { Id = 2, Files = new[] { new { Name = "image.png", Size = 200 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Advanced);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-grid-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithEndsWithOperator()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Files = new[] { new { Name = "document.pdf", Extension = ".pdf" } } },
|
||||
new { Id = 2, Files = new[] { new { Name = "photo.jpg", Extension = ".jpg" } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Advanced);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-grid-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithNotEqualsOperator()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Statuses = new[] { new { Code = "active", Description = "Active" } } },
|
||||
new { Id = 2, Statuses = new[] { new { Code = "inactive", Description = "Inactive" } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("Not equals", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithIsNullOperator()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = (string)null, Value = 10 } } },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag2", Value = 20 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("Is null", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithIsNotNullOperator()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = (string)null, Value = 10 } } },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag2", Value = 20 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("Is not null", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithContainsOperator_InAllModes()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "important", Priority = 1 } } },
|
||||
new { Id = 2, Tags = new[] { new { Name = "normal", Priority = 2 } } }
|
||||
};
|
||||
|
||||
foreach (var mode in new[] { FilterMode.Simple, FilterMode.SimpleWithMenu, FilterMode.Advanced })
|
||||
{
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, mode);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-", component.Markup);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_NumericProperty_WithAllComparisons()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Scores = new[] { new { Value = 90, Subject = "Math" } } },
|
||||
new { Id = 2, Scores = new[] { new { Value = 75, Subject = "Science" } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.SimpleWithMenu);
|
||||
});
|
||||
|
||||
Assert.Contains("Less than or equals", component.Markup);
|
||||
Assert.Contains("Greater than or equals", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_WithCaseInsensitiveFilter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Label = "IMPORTANT" } } },
|
||||
new { Id = 2, Tags = new[] { new { Label = "normal" } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Simple);
|
||||
parameterBuilder.Add<FilterCaseSensitivity>(p => p.FilterCaseSensitivity, FilterCaseSensitivity.CaseInsensitive);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-cell-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_MultipleFilters_WithAndOperator()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Name = "Product1", Tags = new[] { new { Label = "premium", Price = 100 } } },
|
||||
new { Id = 2, Name = "Product2", Tags = new[] { new { Label = "standard", Price = 50 } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Name");
|
||||
builder.AddAttribute(2, "Title", "Name");
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent(3, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(4, "Property", "Id");
|
||||
builder.AddAttribute(5, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Advanced);
|
||||
parameterBuilder.Add<LogicalFilterOperator>(p => p.LogicalFilterOperator, LogicalFilterOperator.And);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-grid-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_NestedProperty()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Details = new { Category = "A" } } } },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Details = new { Category = "B" } } } }
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Advanced);
|
||||
});
|
||||
|
||||
Assert.Contains("rz-grid-filter", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DataGrid_FiltersCollectionItems_LoadDataEvent_TriggeredOnFilter()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.SetupModule("_content/Radzen.Blazor/Radzen.Blazor.js");
|
||||
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1" } } },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag2" } } }
|
||||
};
|
||||
|
||||
var raised = false;
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDataGrid<dynamic>>(parameterBuilder =>
|
||||
{
|
||||
parameterBuilder.Add<IEnumerable<dynamic>>(p => p.Data, testData);
|
||||
parameterBuilder.Add<RenderFragment>(p => p.Columns, builder =>
|
||||
{
|
||||
builder.OpenComponent(0, typeof(RadzenDataGridColumn<dynamic>));
|
||||
builder.AddAttribute(1, "Property", "Id");
|
||||
builder.AddAttribute(2, "Title", "Id");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
parameterBuilder.Add<bool>(p => p.AllowFiltering, true);
|
||||
parameterBuilder.Add<FilterMode>(p => p.FilterMode, FilterMode.Simple);
|
||||
parameterBuilder.Add<LoadDataArgs>(p => p.LoadData, args => { raised = true; });
|
||||
});
|
||||
|
||||
var filterInput = component.Find("input");
|
||||
filterInput.Change("1");
|
||||
|
||||
Assert.True(raised);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,6 +928,767 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Equal(3, result.Count);
|
||||
}
|
||||
|
||||
// Property/FilterProperty tests for collection item filtering
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithEquals()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag1", Value = 50 }, new { Name = "tag5", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = "tag1",
|
||||
FilterOperator = FilterOperator.Equals
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithContains()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "important", Value = 10 }, new { Name = "urgent", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "normal", Value = 30 }, new { Name = "low", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "important", Value = 50 }, new { Name = "high", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = "import",
|
||||
FilterOperator = FilterOperator.Contains
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithStartsWith()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag_alpha", Value = 10 }, new { Name = "tag_beta", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "item_gamma", Value = 30 }, new { Name = "item_delta", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag_epsilon", Value = 50 }, new { Name = "other", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = "tag_",
|
||||
FilterOperator = FilterOperator.StartsWith
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithEndsWith()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "file.txt", Value = 10 }, new { Name = "doc.pdf", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "image.png", Value = 30 }, new { Name = "photo.jpg", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "data.txt", Value = 50 }, new { Name = "info.doc", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = ".txt",
|
||||
FilterOperator = FilterOperator.EndsWith
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithNotEquals()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "active", Value = 10 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "inactive", Value = 20 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "pending", Value = 30 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = "inactive",
|
||||
FilterOperator = FilterOperator.NotEquals
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithDoesNotContain()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "important-task", Value = 10 }, new { Name = "important-note", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "simple", Value = 30 }, new { Name = "basic", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "important-meeting", Value = 50 }, new { Name = "review", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = "important",
|
||||
FilterOperator = FilterOperator.DoesNotContain
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 2);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_Numeric_WithGreaterThan()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag5", Value = 50 }, new { Name = "tag6", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Value",
|
||||
FilterValue = 40,
|
||||
FilterOperator = FilterOperator.GreaterThan
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(3, result[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_Numeric_WithLessThan()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag5", Value = 50 }, new { Name = "tag6", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Value",
|
||||
FilterValue = 25,
|
||||
FilterOperator = FilterOperator.LessThan
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(1, result[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_Numeric_WithGreaterThanOrEquals()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag5", Value = 50 }, new { Name = "tag6", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Value",
|
||||
FilterValue = 50,
|
||||
FilterOperator = FilterOperator.GreaterThanOrEquals
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(3, result[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_Numeric_WithLessThanOrEquals()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag5", Value = 50 }, new { Name = "tag6", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Value",
|
||||
FilterValue = 20,
|
||||
FilterOperator = FilterOperator.LessThanOrEquals
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(1, result[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithIsNull()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = (string)null, Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = (string)null, Value = 50 }, new { Name = "tag6", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterOperator = FilterOperator.IsNull
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithIsNotNull()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = (string)null, Value = 10 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag5", Value = 50 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterOperator = FilterOperator.IsNotNull
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 2);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_CaseInsensitive()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "IMPORTANT", Value = 10 }, new { Name = "urgent", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "normal", Value = 30 }, new { Name = "low", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "Important", Value = 50 }, new { Name = "high", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterValue = "important",
|
||||
FilterOperator = FilterOperator.Contains
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.CaseInsensitive).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_MultipleConditions_WithAnd()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 15 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag1", Value = 50 }, new { Name = "tag5", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Value",
|
||||
FilterValue = 20,
|
||||
FilterOperator = FilterOperator.LessThan,
|
||||
SecondFilterValue = 10,
|
||||
SecondFilterOperator = FilterOperator.GreaterThan,
|
||||
LogicalFilterOperator = LogicalFilterOperator.And
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
// Only items with any tag Value < 20 AND any tag Value > 10
|
||||
Assert.Single(result);
|
||||
Assert.Equal(1, result[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_MultipleConditions_WithOr()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "tag1", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 70 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag1", Value = 50 }, new { Name = "tag5", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Value",
|
||||
FilterValue = 20,
|
||||
FilterOperator = FilterOperator.LessThan,
|
||||
SecondFilterValue = 60,
|
||||
SecondFilterOperator = FilterOperator.GreaterThan,
|
||||
LogicalFilterOperator = LogicalFilterOperator.Or
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
// Items with tags where Value<20 OR Value>60
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithIsEmpty()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "", Value = 10 }, new { Name = "tag2", Value = 20 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 }, new { Name = "tag4", Value = 40 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "", Value = 50 }, new { Name = "tag6", Value = 60 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterOperator = FilterOperator.IsEmpty
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_WithIsNotEmpty()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Tags = new[] { new { Name = "", Value = 10 } }.ToList() },
|
||||
new { Id = 2, Tags = new[] { new { Name = "tag3", Value = 30 } }.ToList() },
|
||||
new { Id = 3, Tags = new[] { new { Name = "tag5", Value = 50 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Name",
|
||||
FilterOperator = FilterOperator.IsNotEmpty
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 2);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersCollectionItemProperty_CombinedWithRegularFilter()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Name = "Product1", Tags = new[] { new { Label = "premium", Price = 100 } }.ToList() },
|
||||
new { Id = 2, Name = "Product2", Tags = new[] { new { Label = "standard", Price = 50 } }.ToList() },
|
||||
new { Id = 3, Name = "Product3", Tags = new[] { new { Label = "premium", Price = 150 } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Tags",
|
||||
FilterProperty = "Label",
|
||||
FilterValue = "premium",
|
||||
FilterOperator = FilterOperator.Equals
|
||||
},
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Name",
|
||||
FilterValue = "Product1",
|
||||
FilterOperator = FilterOperator.Contains
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(1, result[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersNestedCollectionItemProperty()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new { Category = "A" } } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new { Category = "B" } } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new { Category = "A" } } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta.Category",
|
||||
FilterValue = "A",
|
||||
FilterOperator = FilterOperator.Equals
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersNestedCollectionItemProperty_WithIn()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new { Category = "A" } } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new { Category = "B" } } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new { Category = "C" } } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta.Category",
|
||||
FilterValue = new[] { "A", "C" },
|
||||
FilterOperator = FilterOperator.In
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersNestedCollectionItemProperty_WithNotIn()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new { Category = "A" } } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new { Category = "B" } } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new { Category = "C" } } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta.Category",
|
||||
FilterValue = new[] { "A" },
|
||||
FilterOperator = FilterOperator.NotIn
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 2);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersNestedCollectionItemProperty_WithContains()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new { Category = "Alpha" } } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new { Category = "Beta" } } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new { Category = "Alpine" } } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta.Category",
|
||||
FilterValue = "Al",
|
||||
FilterOperator = FilterOperator.Contains
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersNestedCollectionItemProperty_WithDoesNotContain()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new { Category = "Entertainment" } } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new { Category = "Sports" } } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new { Category = "Edutainment" } } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta.Category",
|
||||
FilterValue = "tain",
|
||||
FilterOperator = FilterOperator.DoesNotContain
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
// Excludes categories containing "tain" -> Entertainment, Edutainment
|
||||
Assert.Single(result);
|
||||
Assert.Equal(2, result[0].Id);
|
||||
}
|
||||
|
||||
// Nested collection (Items) with Meta also a collection. Use indexed access to Meta[0].Category
|
||||
[Fact]
|
||||
public void Where_FiltersDoubleNested_WithIn_OnFirstMeta()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new[] { new { Category = "A" }, new { Category = "X" } }.ToList() } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new[] { new { Category = "B" } }.ToList() } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new[] { new { Category = "C" } }.ToList() } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta[0].Category",
|
||||
FilterValue = new[] { "A", "C" },
|
||||
FilterOperator = FilterOperator.In
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersDoubleNested_WithNotIn_OnFirstMeta()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new[] { new { Category = "A" } }.ToList() } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new[] { new { Category = "B" } }.ToList() } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new[] { new { Category = "C" } }.ToList() } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta[0].Category",
|
||||
FilterValue = new[] { "A" },
|
||||
FilterOperator = FilterOperator.NotIn
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 2);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersDoubleNested_WithContains_OnFirstMeta()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new[] { new { Category = "Alpha" } }.ToList() } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new[] { new { Category = "Beta" } }.ToList() } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new[] { new { Category = "Alpine" } }.ToList() } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta[0].Category",
|
||||
FilterValue = "Al",
|
||||
FilterOperator = FilterOperator.Contains
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Contains(result, r => r.Id == 1);
|
||||
Assert.Contains(result, r => r.Id == 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Where_FiltersDoubleNested_WithDoesNotContain_OnFirstMeta()
|
||||
{
|
||||
var testData = new[]
|
||||
{
|
||||
new { Id = 1, Items = new[] { new { Name = "item1", Meta = new[] { new { Category = "Entertainment" } }.ToList() } }.ToList() },
|
||||
new { Id = 2, Items = new[] { new { Name = "item2", Meta = new[] { new { Category = "Sports" } }.ToList() } }.ToList() },
|
||||
new { Id = 3, Items = new[] { new { Name = "item3", Meta = new[] { new { Category = "Edutainment" } }.ToList() } }.ToList() }
|
||||
}.AsQueryable();
|
||||
|
||||
var filters = new List<FilterDescriptor>
|
||||
{
|
||||
new FilterDescriptor
|
||||
{
|
||||
Property = "Items",
|
||||
FilterProperty = "Meta[0].Category",
|
||||
FilterValue = "tain",
|
||||
FilterOperator = FilterOperator.DoesNotContain
|
||||
}
|
||||
};
|
||||
|
||||
var result = testData.Where(filters, LogicalFilterOperator.And, FilterCaseSensitivity.Default).ToList();
|
||||
|
||||
Assert.Single(result);
|
||||
Assert.Equal(2, result[0].Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user