Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advanced query index #480

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/YesSql.Abstractions/IQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public interface IQuery
/// <typeparam name="T">The type of index to return</typeparam>
IQueryIndex<T> ForIndex<T>() where T : class, IIndex;

/// <summary>
/// Defines what type of index should be returned
/// </summary>
/// <typeparam name="T">The type of index to return</typeparam>
IQuery<T> ForIndexJoined<T>() where T : class, IIndex;

/// <summary>
/// Returns documents from any type
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/YesSql.Abstractions/ISqlBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public interface ISqlBuilder
ISqlBuilder Clone();
IEnumerable<string> GetSelectors();
IEnumerable<string> GetOrders();
void Join(JoinType type, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null);
void Join(JoinType type, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null, bool onTableIsAlias = false);
void HavingAnd(string having);
void HavingOr(string having);
}
Expand Down
8 changes: 8 additions & 0 deletions src/YesSql.Abstractions/QueryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ public static IQueryIndex<TIndex> QueryIndex<TIndex>(this ISession session, stri
return session.Query(collection).ForIndex<TIndex>();
}

/// <summary>
/// Creates a query on an index and other joined indexes.
/// </summary>
public static IQuery<TIndex> QueryIndexJoined<TIndex>(this ISession session, string collection = null) where TIndex : class, IIndex
{
return session.Query(collection).ForIndexJoined<TIndex>();
}

/// <summary>
/// Creates a query on an index, with a predicate.
/// </summary>
Expand Down
12 changes: 6 additions & 6 deletions src/YesSql.Abstractions/SqlBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ namespace YesSql;

public static class SqlBuilderExtensions
{
public static void InnerJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null)
=> builder.Join(JoinType.Inner, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias);
public static void InnerJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null, bool onTableIsAlias = false)
=> builder.Join(JoinType.Inner, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias, onTableIsAlias);

public static void LeftJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null)
=> builder.Join(JoinType.Left, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias);
public static void LeftJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null, bool onTableIsAlias = false)
=> builder.Join(JoinType.Left, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias, onTableIsAlias);

public static void RightJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null)
=> builder.Join(JoinType.Right, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias);
public static void RightJoin(this ISqlBuilder builder, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null, bool onTableIsAlias = false)
=> builder.Join(JoinType.Right, table, onTable, onColumn, toTable, toColumn, schema, alias, toAlias, onTableIsAlias);
}
28 changes: 28 additions & 0 deletions src/YesSql.Core/Services/DefaultQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,34 @@ IQueryIndex<TIndex> IQuery.ForIndex<TIndex>()
return new QueryIndex<TIndex>(this);
}

IQuery<TIndex> IQuery.ForIndexJoined<TIndex>()
{
_queryState.GetBindings().Clear();

var tIndex = typeof(TIndex);

var indexTable = _queryState._store.Configuration.TableNameConvention.GetIndexTable(tIndex, _collection);
var indexTableAlias = _queryState.GetTypeAlias(tIndex);

_queryState.AddBinding(tIndex);
_queryState._sqlBuilder.Select();

_queryState._sqlBuilder.Table(indexTable, indexTableAlias, _queryState._store.Configuration.Schema);

_queryState.AddBinding(typeof(Document));

if (typeof(MapIndex).IsAssignableFrom(tIndex))
{
_queryState._sqlBuilder.InnerJoin(_queryState._documentTable, indexTableAlias, "DocumentId", _queryState._documentTable, "Id", _queryState._store.Configuration.Schema, onTableIsAlias: true);
}
else
{
throw new InvalidOperationException("Reduce Indexes are not supported");
}

return new Query<TIndex>(this);
}

IQuery<object> IQuery.Any()
{
_queryState.GetBindings().Clear();
Expand Down
6 changes: 3 additions & 3 deletions src/YesSql.Core/Sql/SqlBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ public void Skip(string skip)
public void Take(string take)
=> _count = take;

public virtual void Join(JoinType type, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null)
public virtual void Join(JoinType type, string table, string onTable, string onColumn, string toTable, string toColumn, string schema, string alias = null, string toAlias = null, bool onTableIsAlias = false)
{
// Don't prefix if alias is used
if (alias != onTable)
if (alias != onTable && !onTableIsAlias)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this, I believe we don't need a new field and just to set the alias argument instead such that it knows that onTable is an alias.

{
onTable = _dialect.QuoteForTableName(onTable, schema);
}
Expand All @@ -92,7 +92,7 @@ public virtual void Join(JoinType type, string table, string onTable, string onC
toTable = _tablePrefix + toTable;
}

if (!string.IsNullOrEmpty(toAlias))
if (!string.IsNullOrEmpty(toAlias) && !onTableIsAlias)
{
toTable = _dialect.QuoteForAliasName(toAlias);
}
Expand Down
92 changes: 91 additions & 1 deletion test/YesSql.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,7 @@ public async Task DetachAllRemoveAllEntitiesFromIdentityMap()
Assert.NotEqual(p3, p3a);

// The identity should be valid as we do only reads

var p1b = await session.GetAsync<Person>(p1.Id);
var p2b = await session.GetAsync<Person>(p2.Id);
var p3b = await session.GetAsync<Person>(p3.Id);
Expand Down Expand Up @@ -1648,6 +1648,96 @@ public async Task ShouldCreateSeveralMapIndexPerDocument()
}
}

[Fact]
public async Task ShouldQueryJoinedIndexes()
{
// We should be able to query documents on multiple rows in multiple index
// This mean the same Index table needs to be JOINed

_store.RegisterIndexes<PersonIdentitiesIndexProvider>();
_store.RegisterIndexes<PersonByNullableAgeIndexProvider>();

using (var session = _store.CreateSession())
{
var hanselman = new Person
{
Firstname = "Scott",
Lastname = "Hanselman",
Age = -1
};

var guthrie = new Person
{
Firstname = "Scott",
Lastname = "Guthrie"
};

await session.SaveAsync(hanselman);
await session.SaveAsync(guthrie);

await session.SaveChangesAsync();
}

using (var session = _store.CreateSession())
{
Assert.Equal(2, await session.QueryIndexJoined<PersonIdentity>()
.All(
x => x.With<PersonByNullableAge>(x => x.Age == null || x.Age == 0),
x => x.Any(
x => x.With<PersonIdentity>(x => x.Identity == "Hanselman"),
x => x.With<PersonIdentity>(x => x.Identity == "Guthrie"))
)
.CountAsync()
);
}
}

[Fact]
public async Task ShouldReturnFirstOrDefaultJoinedIndexes()
{
_store.RegisterIndexes<PersonIndexProvider>();
_store.RegisterIndexes<PersonAgeIndexProvider>();

await using (var session = _store.CreateSession())
{
var bill = new Person { Firstname = "Bill", Lastname = "Gates" };
var scotth = new Person { Firstname = "Scott", Lastname = "Hanselman" };
var scottg = new Person { Firstname = "Scott", Lastname = "Guthrie" };
var scotts = new Person { Firstname = "Scott", Lastname = "Smith", Age = 33 };
var clint = new Person { Firstname = "Clint", Lastname = "Eastwood", Age = 110 };
var smith = new Person { Firstname = "John", Lastname = "Smith", Age = 20 };

await session.SaveAsync(bill);
await session.SaveAsync(scotth);
await session.SaveAsync(scottg);
await session.SaveAsync(scotts);
await session.SaveAsync(smith);
await session.SaveAsync(clint);

await session.SaveChangesAsync();
}

await using (var session = _store.CreateSession())
{
var qry = session.QueryIndexJoined<PersonByAge>()
.Any(d => d.All(
x => x.With<PersonByName>(d => d.SomeName == "Clint" || d.SomeName.StartsWith("S")),
y => y.With<PersonByAge>(d => d.Adult == true)
), d => d.All(
x => x.With<PersonByName>(d => d.SomeName == "Scott"),
y => y.With<PersonByAge>(d => d.Adult == false))
);

var persons = await qry.ListAsync();
Assert.Collection<PersonByAge>(persons,
x => Assert.Equal(110, x.Age),
x => Assert.Equal(0, x.Age),
x => Assert.Equal(0, x.Age)
);
}
}


[Fact]
public async Task ShouldQueryMultipleIndexes()
{
Expand Down
Loading