Skip to content

Commit 526aa5f

Browse files
committed
add where data accessor
1 parent 4518436 commit 526aa5f

File tree

4 files changed

+75
-10
lines changed

4 files changed

+75
-10
lines changed

JsonApiDotNetCore/Data/GenericDataAccess.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,32 @@ public T SingleOrDefault<T>(object query, string param, object value)
4545

4646
return queryable.SingleOrDefault(where);
4747
}
48+
49+
public IQueryable<T> Where<T>(object query, string param, object value)
50+
{
51+
var queryable = (IQueryable<T>) query;
52+
var currentType = queryable.ElementType;
53+
var property = currentType.GetProperty(param);
54+
55+
if (property == null)
56+
{
57+
throw new ArgumentException($"'{param}' is not a valid property of '{currentType}'");
58+
}
59+
60+
// convert the incoming value to the target value type
61+
// "1" -> 1
62+
var convertedValue = Convert.ChangeType(value, property.PropertyType);
63+
// {model}
64+
var prm = Expression.Parameter(currentType, "model");
65+
// {model.Id}
66+
var left = Expression.PropertyOrField(prm, property.Name);
67+
// {1}
68+
var right = Expression.Constant(convertedValue, property.PropertyType);
69+
// {model.Id == 1}
70+
var body = Expression.Equal(left, right);
71+
var where = Expression.Lambda<Func<T, bool>>(body, prm);
72+
73+
return queryable.Where(where);
74+
}
4875
}
4976
}

JsonApiDotNetCore/Data/GenericDataAccessAbstraction.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,35 @@ public GenericDataAccessAbstraction(object dbContext, Type modelType, string inc
2121
_includedRelationship = includedRelationship?.ToProperCase();
2222
}
2323

24-
public object SingleOrDefault(string id)
24+
public object SingleOrDefault(string propertyName, string value)
2525
{
2626
var dbSet = GetDbSet();
27-
if (!string.IsNullOrEmpty(_includedRelationship))
28-
{
29-
dbSet = IncludeRelationshipInContext(dbSet);
30-
}
31-
var dataAccessorSingleOrDefaultMethod = _dataAccessorInstance.GetType().GetMethod("SingleOrDefault");
32-
var genericSingleOrDefaultMethod = dataAccessorSingleOrDefaultMethod.MakeGenericMethod(_modelType);
33-
return genericSingleOrDefaultMethod.Invoke(_dataAccessorInstance, new[] { dbSet, "Id", id });
27+
return InvokeGenericDataAccessMethod("SingleOrDefault", new[] { dbSet, propertyName, value });
28+
}
29+
30+
public object Filter(string propertyName, string value)
31+
{
32+
var dbSet = GetDbSet();
33+
return InvokeGenericDataAccessMethod("Where", new[] { dbSet, propertyName, value });
34+
}
35+
36+
private object InvokeGenericDataAccessMethod(string methodName, params object[] propertyValues)
37+
{
38+
var dataAccessorMethod = _dataAccessorInstance.GetType().GetMethod(methodName);
39+
var genericDataAccessorMethod = dataAccessorMethod.MakeGenericMethod(_modelType);
40+
return genericDataAccessorMethod.Invoke(_dataAccessorInstance, propertyValues);
3441
}
3542

3643
private object GetDbSet()
3744
{
3845
var dataAccessorGetDbSetMethod = _dataAccessorInstance.GetType().GetMethod("GetDbSet");
3946
var genericGetDbSetMethod = dataAccessorGetDbSetMethod.MakeGenericMethod(_modelType);
40-
return genericGetDbSetMethod.Invoke(_dataAccessorInstance, new [] { _dbContext });
47+
var dbSet = genericGetDbSetMethod.Invoke(_dataAccessorInstance, new [] { _dbContext });
48+
if (!string.IsNullOrEmpty(_includedRelationship))
49+
{
50+
dbSet = IncludeRelationshipInContext(dbSet);
51+
}
52+
return dbSet;
4153
}
4254

4355
private object IncludeRelationshipInContext(object dbSet)

JsonApiDotNetCore/Data/ResourceRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private IQueryable GetDbSetFromContext(string propName)
4343

4444
private object GetEntityById(Type modelType, string id, string includedRelationship)
4545
{
46-
return new GenericDataAccessAbstraction(_context.DbContext, modelType, includedRelationship).SingleOrDefault(id);;
46+
return new GenericDataAccessAbstraction(_context.DbContext, modelType, includedRelationship).SingleOrDefault("Id", id);
4747
}
4848

4949
public void Add(object entity)

JsonApiDotNetCoreTests/Data/UnitTests/GenericDataAccessTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,31 @@ public void SingleOrDefault_Fetches_SingleItemFromContext()
3636
Assert.Equal(1, item1.Id);
3737
Assert.Equal(2, item2.Id);
3838
}
39+
40+
[Fact]
41+
public void Where_FetchesRecords_WherePropertyValueEquals_ProvidedValue()
42+
{
43+
// arrange
44+
var data = new List<TodoItem>
45+
{
46+
new TodoItem { Id = 1, Name = "AAA" },
47+
new TodoItem { Id = 2, Name = "AAA" },
48+
new TodoItem { Id = 3, Name = "BBB" }
49+
}.AsQueryable();
50+
51+
var mockSet = new Mock<DbSet<TodoItem>>();
52+
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.Provider).Returns(data.Provider);
53+
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.Expression).Returns(data.Expression);
54+
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.ElementType).Returns(data.ElementType);
55+
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
56+
57+
var genericDataAccess = new GenericDataAccess();
58+
59+
// act
60+
var items = genericDataAccess.Where<TodoItem>(mockSet.Object, "Name", "AAA");
61+
62+
// assert
63+
Assert.Equal(2, items.Count());
64+
}
3965
}
4066
}

0 commit comments

Comments
 (0)