Skip to content

Commit

Permalink
Closes #13. Added WhereNoOp expression to help with complex condition…
Browse files Browse the repository at this point in the history
…al uses of the Query
  • Loading branch information
Jezz Santos committed Aug 25, 2023
1 parent 08840fa commit 79bacb7
Show file tree
Hide file tree
Showing 20 changed files with 1,191 additions and 615 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ OK then, you are going to need help to abstract your persistence layer from your

**QueryAny** was developed to provide developers an easy path to mature from being bound by their incumbent database technology to venture out and consider other persistence technologies. Especially for those developers who have gotten stuck at designing every piece of software they build from a database model upwards (Data Modelers). And don't yet know how to de-couple their domains from their persistence layers.

**QueryAny** prevents developers from having to *leak* database assumptions and dependencies into their domain code, as is a common practice when using ORM libraries and frameworks (eg. Entity Framework, etc). Also, essential for testability, helps developers to swap out their persistence stores when doing various test runs (eg. unit testing versus integration testing). Speed up your testing by a couple orders of magnitude.
**QueryAny** prevents developers from having to
*leak* database assumptions and dependencies into their domain code, as is a common practice when using ORM libraries and frameworks (eg. Entity Framework, etc). Also, essential for testability, helps developers to swap out their persistence stores when doing various test runs (eg. unit testing versus integration testing). Speed up your testing by a couple orders of magnitude.

We wanted developers to be able to define their own simple repository interface (eg. `IStorage<TEntity>`), and have that as the only dependency in their domain code. Then, be able to implement that interface in any chosen database technology, and plug it in at runtime.

Expand Down
18 changes: 9 additions & 9 deletions samples/ri/Storage.Azure/AzureTableStorageRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ private static EntityProperty ToTableEntityProperty(object property, Type target
{
switch (targetPropertyType)
{
case Type _ when targetPropertyType == typeof(DateTime) || targetPropertyType == typeof(DateTime?):
case not null when targetPropertyType == typeof(DateTime) || targetPropertyType == typeof(DateTime?):
{
DateTimeOffset? dateTimeOffset = null;
var dateTime = (DateTime?) property;
Expand All @@ -444,8 +444,8 @@ private static EntityProperty ToTableEntityProperty(object property, Type target
return EntityProperty.GeneratePropertyForDateTimeOffset(dateTimeOffset);
}

case Type _ when targetPropertyType == typeof(DateTimeOffset) ||
targetPropertyType == typeof(DateTimeOffset?):
case not null when targetPropertyType == typeof(DateTimeOffset) ||
targetPropertyType == typeof(DateTimeOffset?):
{
var dateTimeOffset = (DateTimeOffset?) property;
if (dateTimeOffset.HasValue)
Expand All @@ -458,22 +458,22 @@ private static EntityProperty ToTableEntityProperty(object property, Type target
return EntityProperty.GeneratePropertyForDateTimeOffset(dateTimeOffset);
}

case Type _ when targetPropertyType == typeof(bool) || targetPropertyType == typeof(bool?):
case not null when targetPropertyType == typeof(bool) || targetPropertyType == typeof(bool?):
return EntityProperty.GeneratePropertyForBool((bool?) property);

case Type _ when targetPropertyType == typeof(int) || targetPropertyType == typeof(int?):
case not null when targetPropertyType == typeof(int) || targetPropertyType == typeof(int?):
return EntityProperty.GeneratePropertyForInt((int?) property);

case Type _ when targetPropertyType == typeof(long) || targetPropertyType == typeof(long?):
case not null when targetPropertyType == typeof(long) || targetPropertyType == typeof(long?):
return EntityProperty.GeneratePropertyForLong((long?) property);

case Type _ when targetPropertyType == typeof(double) || targetPropertyType == typeof(double?):
case not null when targetPropertyType == typeof(double) || targetPropertyType == typeof(double?):
return EntityProperty.GeneratePropertyForDouble((double?) property);

case Type _ when targetPropertyType == typeof(Guid) || targetPropertyType == typeof(Guid?):
case not null when targetPropertyType == typeof(Guid) || targetPropertyType == typeof(Guid?):
return EntityProperty.GeneratePropertyForGuid((Guid?) property);

case Type _ when targetPropertyType == typeof(byte[]):
case not null when targetPropertyType == typeof(byte[]):
return EntityProperty.GeneratePropertyForByteArray((byte[]) property);

default:
Expand Down
210 changes: 210 additions & 0 deletions src/QueryAny.UnitTests/FromClauseSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
using System;
using FluentAssertions;
using QueryAny.Properties;
using Xunit;

namespace QueryAny.UnitTests
{
[Trait("Category", "Unit")]
public class FromClauseSpec
{
[Fact]
public void WhenWhereAndHasWhereNoOp_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.WhereNoOp();

query
.Invoking(x => x.Where(e => e.AStringProperty, ConditionOperator.EqualTo, "1"))
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereAndNotEmpty);
}

[Fact]
public void WhenWhereAndHasWhereAll_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.WhereAll();

query
.Invoking(x => x.Where(e => e.AStringProperty, ConditionOperator.EqualTo, "1"))
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereAndNotEmpty);
}

[Fact]
public void WhenWhereAndHasWhere_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.Where(e => e.AStringProperty, ConditionOperator.EqualTo, "1");

query
.Invoking(x => x.Where(e => e.AStringProperty, ConditionOperator.EqualTo, "1"))
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereAndNotEmpty);
}

[Fact]
public void WhenWhereWithStringProperty_ThenCreatesAWhere()
{
var query = Query.From<NamedTestEntity>();

var result = query
.Where(e => e.AStringProperty, ConditionOperator.EqualTo, "1");

result.Wheres.Count.Should().Be(1);
result.Wheres[0].Operator.Should().Be(LogicalOperator.None);
result.Wheres[0].Condition.Operator.Should().Be(ConditionOperator.EqualTo);
result.Wheres[0].Condition.FieldName.Should().Be("AStringProperty");
result.Wheres[0].Condition.Value.Should().Be("1");
}

[Fact]
public void WhenWhereWithDateTimeProperty_ThenCreatesAWhere()
{
var datum = DateTime.UtcNow;
var query = Query.From<NamedTestEntity>();

var result = query
.Where(e => e.ADateTimeProperty, ConditionOperator.EqualTo, datum);

result.Wheres.Count.Should().Be(1);
result.Wheres[0].Operator.Should().Be(LogicalOperator.None);
result.Wheres[0].Condition.Operator.Should().Be(ConditionOperator.EqualTo);
result.Wheres[0].Condition.FieldName.Should().Be("ADateTimeProperty");
result.Wheres[0].Condition.Value.Should().Be(datum);
}

[Fact]
public void WhenWhereAllAndHasWhereNoOp_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.WhereNoOp();

query
.Invoking(x => x.WhereAll())
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereAllAndNotEmpty);
}

[Fact]
public void WhenWhereAllAndHasWheres_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.Where(entity => entity.AStringProperty, ConditionOperator.EqualTo, "avalue");

query
.Invoking(x => x.WhereAll())
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereAllAndNotEmpty);
}

[Fact]
public void WhenWhereAllAndHasWhereAll_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.WhereAll();

query
.Invoking(x => x.WhereAll())
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereAllAndNotEmpty);
}

[Fact]
public void WhenWhereAll_ThenReturnsQueryClauseWithAllWheres()
{
var query = Query.From<NamedTestEntity>();

var result = query.WhereAll();

result.Wheres.Count.Should().Be(0);
result.Options.Wheres.Should().Be(WhereOptions.AllDefined);
}

[Fact]
public void WhenWhereNoOpAndHasWhereNoOp_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.WhereNoOp();

query
.Invoking(x => x.WhereNoOp())
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereNoOpAndNotEmpty);
}

[Fact]
public void WhenWhereNoOpAndHasWheres_ThenThrows()
{
var query = Query.From<NamedTestEntity>();
query.Where(entity => entity.AStringProperty, ConditionOperator.EqualTo, "avalue");

query
.Invoking(x => x.WhereNoOp())
.Should().Throw<InvalidOperationException>()
.WithMessage(Resources.FromClause_WhereNoOpAndNotEmpty);
}

[Fact]
public void WhenWhereNoOp_ThenReturnsQueryClauseWithSpecificWheres()
{
var query = Query.From<NamedTestEntity>();

var result = query.WhereNoOp();

result.Wheres.Count.Should().Be(0);
result.Options.Wheres.Should().Be(WhereOptions.SomeDefined);
}

[Fact]
public void WhenJoin_ThenCreatesAnInnerJoin()
{
var query = Query.From<FirstTestEntity>();
var result = query
.Join<SecondTestEntity, string>(f => f.AFirstStringProperty, s => s.ASecondStringProperty)
.Where(e => e.AFirstStringProperty, ConditionOperator.EqualTo, "avalue");

result.AllEntities.Count.Should().Be(2);
result.PrimaryEntity.Join.Should().BeNull();
result.AllEntities[1].Join.Left.EntityName.Should().Be("first");
result.AllEntities[1].Join.Left.JoinedFieldName.Should().Be("AFirstStringProperty");
result.AllEntities[1].Join.Right.EntityName.Should().Be("second");
result.AllEntities[1].Join.Right.JoinedFieldName.Should().Be("ASecondStringProperty");
result.AllEntities[1].Join.Type.Should().Be(JoinType.Inner);
}

[Fact]
public void WhenTake_ThenLimitIsSet()
{
var query = Query.From<NamedTestEntity>();

var results = query
.Take(10);

results.ResultOptions.Limit.Should().Be(10);
}

[Fact]
public void WhenSkip_ThenLimitIsSet()
{
var query = Query.From<NamedTestEntity>();

var results = query
.Skip(10);

results.ResultOptions.Offset.Should().Be(10);
}

[Fact]
public void WhenOrderBy_ThenSetsOrder()
{
var query = Query.From<NamedTestEntity>();

var result = query.OrderBy(e => e.AStringProperty);

result.ResultOptions.OrderBy.By.Should().Be("AStringProperty");
result.ResultOptions.OrderBy.Direction.Should().Be(OrderDirection.Ascending);
}
}
}
Loading

0 comments on commit 79bacb7

Please sign in to comment.