Skip to content

Commit f447066

Browse files
authored
Merge pull request #20 from hdimon/mapping_fixes
Hidden fields and mappings fixes.
2 parents aef016e + e935c60 commit f447066

File tree

9 files changed

+274
-2
lines changed

9 files changed

+274
-2
lines changed

src/FlexFetcher/Models/FlexFetcherOptions/BaseFlexOptions.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,25 @@ public bool TryGetFieldNameByAlias(string alias,
7575
/// <summary>
7676
/// Hides all original fields of Entity from sorting/filtering,
7777
/// i.e. if fields are hidden then they can be accessed only by their aliases.
78-
/// Field aliases are not affected by this method.
78+
/// Field aliases are not affected by this method even if they are equal to original fields
79+
/// (it's possible to create alias "Name" for field "Name" even if it's the same).
7980
/// </summary>
8081
public void HideOriginalFields()
8182
{
8283
OriginalFieldsHidden = true;
8384
}
8485

86+
/// <summary>
87+
/// It's valid situation when field has alias equal to its name.
88+
/// In this case, even if field is hidden, it can be accessed by its alias, so this method returns false.
89+
/// </summary>
90+
/// <param name="fieldName"></param>
91+
/// <returns></returns>
8592
public bool IsHiddenField(string fieldName)
8693
{
94+
if (TryGetFieldNameByAlias(fieldName, out _))
95+
return false;
96+
8797
return HiddenFields.Contains(fieldName);
8898
}
8999

src/FlexFetcher/Utils/FieldBuilder.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,23 @@ public override void Build()
4949

5050
foreach (var expression in _expressions)
5151
{
52-
var alias = ((MemberExpression)expression.Body).Member.Name;
52+
var alias = GetMemberName(expression.Body);
5353
_aliases.Add(alias);
5454
}
5555
}
56+
57+
private static string GetMemberName(Expression expression)
58+
{
59+
if (expression is MemberExpression memberExpression)
60+
{
61+
return memberExpression.Member.Name;
62+
}
63+
64+
if (expression is UnaryExpression { Operand: MemberExpression operand })
65+
{
66+
return operand.Member.Name;
67+
}
68+
69+
throw new InvalidOperationException("Invalid expression type.");
70+
}
5671
}

tests/FlexFetcherTests/FlexFilterTests/BaseFilterData.cs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,30 @@ protected void SimpleValueObjectFilterWithFieldAliasTest(Func<DataFilter, FlexFi
300300
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1, 3, 5, 7, 9 }));
301301
}
302302

303+
protected void SimpleValueObjectFilterWithTheSameFieldAliasTest(Func<DataFilter, FlexFilterOptions<PeopleEntity>, List<PeopleEntity>> fetcher)
304+
{
305+
var filter = new DataFilter
306+
{
307+
Filters = new List<DataFilter>
308+
{
309+
new()
310+
{
311+
Field = "PeopleName",
312+
Operator = DataFilterOperator.Equal,
313+
Value = "John"
314+
}
315+
}
316+
};
317+
318+
var options = new FlexFilterOptions<PeopleEntity>();
319+
options.Field(x => x.PeopleName).CastTo<string>().Map("PeopleName");
320+
321+
var result = fetcher(filter, options);
322+
323+
Assert.That(result.Count, Is.EqualTo(5));
324+
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1, 3, 5, 7, 9 }));
325+
}
326+
303327
protected void SimpleNestedEntityFilterWithFieldAliasTest(Func<FlexFilter<PeopleEntity>, DataFilter, List<PeopleEntity>> fetcher)
304328
{
305329
var filter = new DataFilter
@@ -336,6 +360,42 @@ protected void SimpleNestedEntityFilterWithFieldAliasTest(Func<FlexFilter<People
336360
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1 }));
337361
}
338362

363+
protected void SimpleNestedEntityFilterWithTheSameFieldAliasTest(Func<FlexFilter<PeopleEntity>, DataFilter, List<PeopleEntity>> fetcher)
364+
{
365+
var filter = new DataFilter
366+
{
367+
Logic = DataFilterLogic.And,
368+
Filters = new List<DataFilter>
369+
{
370+
new()
371+
{
372+
Field = "Address",
373+
Operator = DataFilterOperator.NotEqual,
374+
Value = null
375+
},
376+
new()
377+
{
378+
Field = "Address.City",
379+
Operator = DataFilterOperator.Equal,
380+
Value = "New York"
381+
}
382+
}
383+
};
384+
385+
var addressOption = new FlexFilterOptions<AddressEntity>();
386+
addressOption.Field(x => x.City).Map("City");
387+
var addressFilter = new FlexFilter<AddressEntity>(addressOption);
388+
var peopleOption = new FlexFilterOptions<PeopleEntity>();
389+
peopleOption.AddNestedFlexFilter(addressFilter);
390+
peopleOption.Field(x => x.Address).Map("Address");
391+
var peopleFilter = new FlexFilter<PeopleEntity>(peopleOption);
392+
393+
var result = fetcher(peopleFilter, filter);
394+
395+
Assert.That(result.Count, Is.EqualTo(1));
396+
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1 }));
397+
}
398+
339399
protected void SimpleNestedEntityFilterWithFieldAliasByFlexFilterTest(Func<SimpleNestedEntityPeopleFilterWithFieldAlias, DataFilter, List<PeopleEntity>> fetcher)
340400
{
341401
var filter = new DataFilter
@@ -629,6 +689,48 @@ protected void SimpleFilterWithHiddenFieldTest(Func<DataFilter, List<PeopleEntit
629689
});
630690
}
631691

692+
protected void SimpleFilterWithHiddenFieldAndTheSameMappingTest(Func<DataFilter, List<PeopleEntity>> filter)
693+
{
694+
var filters = new DataFilter
695+
{
696+
Filters = new List<DataFilter>
697+
{
698+
new DataFilter
699+
{
700+
Field = "CreatedByUserId",
701+
Operator = DataFilterOperator.Equal,
702+
Value = 1
703+
}
704+
}
705+
};
706+
707+
var result = filter(filters);
708+
709+
Assert.That(result.Count, Is.EqualTo(3));
710+
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1, 2, 3 }));
711+
}
712+
713+
protected void SimpleValueObjectFilterWithHiddenFieldAndTheSameMappingTest(Func<DataFilter, List<PeopleEntity>> filter)
714+
{
715+
var filters = new DataFilter
716+
{
717+
Filters = new List<DataFilter>
718+
{
719+
new DataFilter
720+
{
721+
Field = "PeopleCreatedByUserId",
722+
Operator = DataFilterOperator.Equal,
723+
Value = 1
724+
}
725+
}
726+
};
727+
728+
var result = filter(filters);
729+
730+
Assert.That(result.Count, Is.EqualTo(3));
731+
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1, 2, 3 }));
732+
}
733+
632734
protected void SimpleFilterWithNotFoundFieldTest(Func<DataFilter, List<PeopleEntity>> filter)
633735
{
634736
var filters = new DataFilter

tests/FlexFetcherTests/FlexFilterTests/FilterDataEnumerableTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using FlexFetcherTests.Stubs.FlexFetcherContexts;
99
using TestData;
1010
using TestData.Database;
11+
using TestData.Database.ValueObjects;
1112

1213
namespace FlexFetcherTests.FlexFilterTests;
1314

@@ -248,11 +249,40 @@ public void SimpleFilterWithAllHiddenOriginalFields()
248249
SimpleFilterWithHiddenFieldTest(sorters => flexFilter.FilterData(_people, sorters).ToList());
249250
}
250251

252+
[Test]
253+
public void SimpleFilterWithHiddenFieldAndTheSameMapping()
254+
{
255+
var options = new FlexFilterOptions<PeopleEntity, PeopleModelWithTheSameField>();
256+
options.HideOriginalFields();
257+
options.Field(x => x.CreatedByUserId).Map(model => model.CreatedByUserId)
258+
.Map(nameof(PeopleModelWithTheSameField.CreatedByUserId));
259+
var flexFilter = new FlexFilter<PeopleEntity, PeopleModelWithTheSameField>(options);
260+
SimpleFilterWithHiddenFieldAndTheSameMappingTest(sorters => flexFilter.FilterData(_people, sorters).ToList());
261+
}
262+
263+
[Test]
264+
public void SimpleValueObjectFilterWithHiddenFieldAndTheSameMapping()
265+
{
266+
var options = new FlexFilterOptions<PeopleEntity, PeopleModelWithTheSameField>();
267+
options.HideOriginalFields();
268+
options.Field(x => x.PeopleCreatedByUserId).CastTo<int>().Map(model => model.CreatedByUserId)
269+
.Map(model => model.PeopleCreatedByUserId).Map(nameof(PeopleModelWithTheSameField.CreatedByUserId))
270+
.Map(nameof(PeopleModelWithTheSameField.PeopleCreatedByUserId));
271+
var flexFilter = new FlexFilter<PeopleEntity, PeopleModelWithTheSameField>(options);
272+
SimpleValueObjectFilterWithHiddenFieldAndTheSameMappingTest(sorters => flexFilter.FilterData(_people, sorters).ToList());
273+
}
274+
251275
[Test]
252276
public void SimpleFilterWithNotFoundField()
253277
{
254278
var options = new FlexFilterOptions<PeopleEntity>();
255279
var flexFilter = new FlexFilter<PeopleEntity>(options);
256280
SimpleFilterWithNotFoundFieldTest(sorters => flexFilter.FilterData(_people, sorters).ToList());
257281
}
282+
283+
private class PeopleModelWithTheSameField
284+
{
285+
public int CreatedByUserId { get; set; }
286+
public PeopleCreatedByUserId PeopleCreatedByUserId { get; set; } = null!;
287+
}
258288
}

tests/FlexFetcherTests/FlexFilterTests/FilterDataQueryableTests.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,49 @@ public void SimpleValueObjectFilterWithFieldAlias()
160160
SimpleValueObjectFilterWithFieldAliasTest((filters, _) => flexFilter.FilterData(_ctx.People, filters).ToList());
161161
}
162162

163+
[Test]
164+
public void SimpleValueObjectFilterWithTheSameFieldAlias()
165+
{
166+
SimpleValueObjectFilterWithTheSameFieldAliasTest((filters, options) => _ctx.People.FilterData(filters, options).ToList());
167+
168+
var flexFilter = new PeopleFilterWithTheSameAlias();
169+
SimpleValueObjectFilterWithTheSameFieldAliasTest((filters, _) => flexFilter.FilterData(_ctx.People, filters).ToList());
170+
}
171+
172+
[Test]
173+
public void SimpleValueObjectFilterWithTheSameModelFieldAlias()
174+
{
175+
var filter = new DataFilter
176+
{
177+
Filters = new List<DataFilter>
178+
{
179+
new()
180+
{
181+
Field = "PeopleName",
182+
Operator = DataFilterOperator.Equal,
183+
Value = "John"
184+
}
185+
}
186+
};
187+
188+
var options = new FlexFilterOptions<PeopleEntity, PeopleEntityWithTheSameFieldAlias>();
189+
options.Field(x => x.PeopleName).CastTo<string>().Map(model => model.PeopleName);
190+
var flexFilter = new FlexFilter<PeopleEntity>(options);
191+
192+
var result = flexFilter.FilterData(_ctx.People, filter).ToList();
193+
194+
Assert.That(result.Count, Is.EqualTo(5));
195+
Assert.That(result.Select(p => p.Id).ToList(), Is.EquivalentTo(new List<int> { 1, 3, 5, 7, 9 }));
196+
197+
198+
SimpleValueObjectFilterWithTheSameFieldAliasTest((filters, _) => flexFilter.FilterData(_ctx.People, filters).ToList());
199+
}
200+
201+
private class PeopleEntityWithTheSameFieldAlias
202+
{
203+
public string PeopleName { get; set; } = null!;
204+
}
205+
163206
private class PeopleFilter : FlexFilter<PeopleEntity>
164207
{
165208
public PeopleFilter()
@@ -168,6 +211,14 @@ public PeopleFilter()
168211
}
169212
}
170213

214+
private class PeopleFilterWithTheSameAlias : FlexFilter<PeopleEntity>
215+
{
216+
public PeopleFilterWithTheSameAlias()
217+
{
218+
Options.Field(x => x.PeopleName).CastTo<string>().Map("PeopleName");
219+
}
220+
}
221+
171222
[Test]
172223
public void SimpleFilterWithDefaultAndLogic()
173224
{
@@ -239,6 +290,24 @@ public void SimpleNestedEntityFilterWithFieldAlias()
239290
peopleFilterModel.FilterData(_ctx.People.Include(p => p.Address), filters).ToList());
240291
}
241292

293+
[Test]
294+
public void SimpleNestedEntityFilterWithTheSameFieldAlias()
295+
{
296+
SimpleNestedEntityFilterWithTheSameFieldAliasTest((flexFilter, filters) =>
297+
flexFilter.FilterData(_ctx.People.Include(p => p.Address), filters).ToList());
298+
299+
// With model
300+
var addressOptionsModel = new FlexFilterOptions<AddressEntity, IdenticalAddressModel>();
301+
addressOptionsModel.Field(x => x.City).Map(model => model.City).Map("City");
302+
var addressFilterModel = new FlexFilter<AddressEntity>(addressOptionsModel);
303+
var peopleOptionsModel = new FlexFilterOptions<PeopleEntity, IdenticalPeopleModel>();
304+
peopleOptionsModel.AddNestedFlexFilter(addressFilterModel);
305+
peopleOptionsModel.Field(x => x.Address).Map(model => model.Address).Map("Address");
306+
var peopleFilterModel = new FlexFilter<PeopleEntity>(peopleOptionsModel);
307+
SimpleNestedEntityFilterWithTheSameFieldAliasTest((_, filters) =>
308+
peopleFilterModel.FilterData(_ctx.People.Include(p => p.Address), filters).ToList());
309+
}
310+
242311
private class PeopleModel
243312
{
244313
public AddressModel Residence { get; set; } = null!;
@@ -249,6 +318,16 @@ private class AddressModel
249318
public string Town { get; set; } = null!;
250319
}
251320

321+
private class IdenticalPeopleModel
322+
{
323+
public IdenticalAddressModel Address { get; set; } = null!;
324+
}
325+
326+
private class IdenticalAddressModel
327+
{
328+
public string City { get; set; } = null!;
329+
}
330+
252331
[Test]
253332
public void SimpleNestedEntityFilterWithFieldAliasByFlexFilter()
254333
{

tests/FlexFetcherTests/Stubs/Database/TestDbContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
2020
modelBuilder.Entity<PeopleEntity>().HasKey(p => p.Id);
2121
modelBuilder.Entity<PeopleEntity>().Property(p => p.Occupation).HasConversion<string>();
2222
modelBuilder.Entity<PeopleEntity>().Property(p => p.PeopleName).HasConversion(v => v!.Value, v => new PeopleName(v));
23+
modelBuilder.Entity<PeopleEntity>().Property(p => p.PeopleCreatedByUserId)
24+
.HasConversion(v => v.Value, v => new PeopleCreatedByUserId(v));
2325

2426
modelBuilder.Entity<AddressEntity>().HasKey(a => a.Id);
2527
modelBuilder.Entity<UserEntity>().HasKey(a => a.Id);

tests/TestData/Database/PeopleEntity.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class PeopleEntity
3030
public string? Email { get; set; }
3131
public Occupation? Occupation { get; set; }
3232
public int CreatedByUserId { get; set; }
33+
public PeopleCreatedByUserId PeopleCreatedByUserId { get; set; } = null!;
3334
public UserEntity? CreatedByUser { get; set; }
3435
public int? UpdatedByUserId { get; set; }
3536
public UserEntity? UpdatedByUser { get; set; }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace TestData.Database.ValueObjects;
2+
3+
public class PeopleCreatedByUserId : ValueObjectBase
4+
{
5+
public int Value { get; }
6+
7+
public PeopleCreatedByUserId(int value)
8+
{
9+
Value = value;
10+
}
11+
12+
public static implicit operator int(PeopleCreatedByUserId createdByUserId) => createdByUserId.Value;
13+
14+
public override string ToString()
15+
{
16+
return Value.ToString();
17+
}
18+
19+
protected override IEnumerable<object> GetEqualityComponents()
20+
{
21+
yield return Value;
22+
}
23+
}

0 commit comments

Comments
 (0)