Skip to content

Commit

Permalink
Merge pull request #174 from mfenniak/issue_174
Browse files Browse the repository at this point in the history
Support multi-indexes in IndexDefine
  • Loading branch information
mfenniak committed Oct 21, 2014
2 parents 6c3bbc8 + b805325 commit e501f46
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 23 deletions.
7 changes: 7 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# rethinkdb-net Release Notes

## Next Release

### Features

* The type-safe object model for secondary indexes has been expanded to incldude multi-indexes. Calling table.IndexDefineMulti will return an IMultiIndex<TRecord, TIndexType> interface that can be used in multi-index operations, such as GetAll, Between, and EqJoin.


## 0.8.0.0 (2014-10-20)

### Features
Expand Down
40 changes: 36 additions & 4 deletions rethinkdb-net-test/Integration/MultiTableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq.Expressions;
using FluentAssertions;

namespace RethinkDb.Test.Integration
{
Expand All @@ -15,6 +16,7 @@ public class MultiTableTests : TestBase
private ITableQuery<TestObject> testTable;
private ITableQuery<AnotherTestObject> anotherTestTable;
private IIndex<AnotherTestObject, string> firstNameIndex;
private IMultiIndex<TestObject, string> tagsIndex;

public override void TestFixtureSetUp()
{
Expand All @@ -28,16 +30,19 @@ public override void TestFixtureSetUp()

firstNameIndex = anotherTestTable.IndexDefine("index1", o => o.FirstName);
connection.Run(firstNameIndex.IndexCreate());

tagsIndex = testTable.IndexDefineMulti("indexTags", o => o.Tags);
connection.Run(tagsIndex.IndexCreate());
}

[SetUp]
public virtual void SetUp()
{
connection.RunAsync(testTable.Insert(new TestObject[] {
new TestObject() { Id = "1", Name = "1", SomeNumber = 1, Children = new TestObject[1], ChildrenList = new List<TestObject> { null }, ChildrenIList = new List<TestObject> { null } },
new TestObject() { Id = "2", Name = "2", SomeNumber = 2, Children = new TestObject[2], ChildrenList = new List<TestObject> { null, null }, ChildrenIList = new List<TestObject> { null, null } },
new TestObject() { Id = "3", Name = "3", SomeNumber = 3, Children = new TestObject[3], ChildrenList = new List<TestObject> { null, null, null }, ChildrenIList = new List<TestObject> { null, null, null } },
new TestObject() { Id = "4", Name = "4", SomeNumber = 4, Children = new TestObject[4], ChildrenList = new List<TestObject> { null, null, null, null }, ChildrenIList = new List<TestObject> { null, null, null, null } },
new TestObject() { Id = "1", Name = "1", SomeNumber = 1, Tags = new[] { "1", "5" }, Children = new TestObject[1], ChildrenList = new List<TestObject> { null }, ChildrenIList = new List<TestObject> { null } },
new TestObject() { Id = "2", Name = "2", SomeNumber = 2, Tags = new[] { "2", "6" }, Children = new TestObject[2], ChildrenList = new List<TestObject> { null, null }, ChildrenIList = new List<TestObject> { null, null } },
new TestObject() { Id = "3", Name = "3", SomeNumber = 3, Tags = new[] { "3", "7" }, Children = new TestObject[3], ChildrenList = new List<TestObject> { null, null, null }, ChildrenIList = new List<TestObject> { null, null, null } },
new TestObject() { Id = "4", Name = "4", SomeNumber = 4, Tags = new[] { "4", "8" }, Children = new TestObject[4], ChildrenList = new List<TestObject> { null, null, null, null }, ChildrenIList = new List<TestObject> { null, null, null, null } },
})).Wait();

connection.RunAsync(anotherTestTable.Insert(new AnotherTestObject[] {
Expand Down Expand Up @@ -245,6 +250,33 @@ public void EqJoinIndexObject()
Assert.That(objects, Has.Count.EqualTo(3));
}

[Test]
public void EqJoinMultiIndex()
{
var enumerable = connection.Run(
anotherTestTable.EqJoin(
anotherTestObject => anotherTestObject.FirstName,
testTable,
tagsIndex
)
);
Assert.That(enumerable, Is.Not.Null);

var objects = new List<Tuple<AnotherTestObject, TestObject>>();
var count = 0;
foreach (var tup in enumerable)
{
objects.Add(tup);
++count;

Assert.That(tup.Item1, Is.Not.Null);
Assert.That(tup.Item2, Is.Not.Null);
tup.Item2.Tags.Should().Contain(tup.Item1.FirstName);
}
Assert.That(count, Is.EqualTo(3));
Assert.That(objects, Has.Count.EqualTo(3));
}

[Test]
public void Zip()
{
Expand Down
37 changes: 37 additions & 0 deletions rethinkdb-net-test/Integration/TableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,43 @@ public void IndexCreateMulti()
Assert.That(stronglyTyped.All(x => x.Name != languages[2].Name));
}

[Test]
public void IndexCreateMultiObjectModel()
{
var languages = new[]
{
new TestObject
{
Name = "C#",
Tags = new[] {"dynamic", "lambdas", "object-oriented", "strongly-typed", "generics"}
},
new TestObject
{
Name = "java",
Tags = new[] {"object-oriented", "strongly-typed", "generics"}
},
new TestObject
{
Name = "javascript",
Tags = new[] {"dynamic"}
}
};

var resp = connection.Run(testTable.Insert(languages));
Assert.That(resp.Inserted, Is.EqualTo(3));

var index = testTable.IndexDefineMulti("index_tags", x => x.Tags);
resp = connection.Run(index.IndexCreate());
Assert.That(resp.Created, Is.EqualTo(1));

//and query
var stronglyTyped = connection.Run(index.GetAll("strongly-typed")).ToArray();

Assert.That(stronglyTyped, Is.Not.Null);
Assert.That(stronglyTyped.Length, Is.EqualTo(2));
Assert.That(stronglyTyped.All(x => x.Name != languages[2].Name));
}

[Test]
public void IndexList()
{
Expand Down
13 changes: 13 additions & 0 deletions rethinkdb-net/Interfaces/IBaseIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace RethinkDb
{
[ImmutableObject(true)]
public interface IBaseIndex<TRecord, TIndex>
{
ITableQuery<TRecord> Table { get; }
string Name { get; }
}
}
4 changes: 1 addition & 3 deletions rethinkdb-net/Interfaces/IIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
namespace RethinkDb
{
[ImmutableObject(true)]
public interface IIndex<TRecord, TIndex>
public interface IIndex<TRecord, TIndex> : IBaseIndex<TRecord, TIndex>
{
ITableQuery<TRecord> Table { get; }
string Name { get; }
Expression<Func<TRecord, TIndex>> IndexAccessor { get; }
}
}
13 changes: 13 additions & 0 deletions rethinkdb-net/Interfaces/IMultiIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;

namespace RethinkDb
{
[ImmutableObject(true)]
public interface IMultiIndex<TRecord, TIndex> : IBaseIndex<TRecord, TIndex>
{
Expression<Func<TRecord, IEnumerable<TIndex>>> IndexAccessor { get; }
}
}
35 changes: 35 additions & 0 deletions rethinkdb-net/MultiIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace RethinkDb
{
public class MultiIndex<TRecord, TIndex> : IMultiIndex<TRecord, TIndex>
{
private readonly ITableQuery<TRecord> table;
private readonly string name;
private readonly Expression<Func<TRecord, IEnumerable<TIndex>>> indexAccessor;

public MultiIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, IEnumerable<TIndex>>> indexAccessor)
{
this.table = table;
this.name = name;
this.indexAccessor = indexAccessor;
}

public ITableQuery<TRecord> Table
{
get { return table; }
}

public string Name
{
get { return name; }
}

public Expression<Func<TRecord, IEnumerable<TIndex>>> IndexAccessor
{
get { return indexAccessor; }
}
}
}
32 changes: 26 additions & 6 deletions rethinkdb-net/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,22 @@ public static IIndex<TRecord, TIndex> IndexDefine<TRecord, TIndex>(this ITableQu
return new Index<TRecord, TIndex>(table, name, indexAccessor);
}

public static IMultiIndex<TRecord, TIndex> IndexDefineMulti<TRecord, TIndex>(this ITableQuery<TRecord> table, string name, Expression<Func<TRecord, IEnumerable<TIndex>>> indexAccessor)
{
return new MultiIndex<TRecord, TIndex>(table, name, indexAccessor);
}

public static IWriteQuery<DmlResponse> IndexCreate<TRecord, TIndex>(this IIndex<TRecord, TIndex> index)
{
return index.Table.IndexCreate(index.Name, index.IndexAccessor, false);
}

public static IWriteQuery<DmlResponse> IndexDrop<TRecord, TIndex>(this IIndex<TRecord, TIndex> index)
public static IWriteQuery<DmlResponse> IndexCreate<TRecord, TIndex>(this IMultiIndex<TRecord, TIndex> index)
{
return index.Table.IndexCreate(index.Name, index.IndexAccessor, true);
}

public static IWriteQuery<DmlResponse> IndexDrop<TRecord, TIndex>(this IBaseIndex<TRecord, TIndex> index)
{
return index.Table.IndexDrop(index.Name);
}
Expand Down Expand Up @@ -110,12 +120,22 @@ public static IMutableSingleObjectQuery<T> Get<T>(this ISequenceQuery<T> target,

public static ISequenceQuery<TSequence> GetAll<TSequence, TKey>(this ISequenceQuery<TSequence> target, TKey key, string indexName = null)
{
return new GetAllQuery<TSequence, TKey>(target, key, indexName);
return new GetAllQuery<TSequence, TKey>(target, new TKey[] { key }, indexName);
}

public static ISequenceQuery<TSequence> GetAll<TSequence, TKey>(this ISequenceQuery<TSequence> target, TKey[] keys, string indexName = null)
{
return new GetAllQuery<TSequence, TKey>(target, keys, indexName);
}

public static ISequenceQuery<TSequence> GetAll<TSequence, TKey>(this ISequenceQuery<TSequence> target, TKey key, IBaseIndex<TSequence, TKey> index)
{
return target.GetAll(key, indexName: index.Name);
}

public static ISequenceQuery<TSequence> GetAll<TSequence, TKey>(this ISequenceQuery<TSequence> target, TKey key, IIndex<TSequence, TKey> index)
public static ISequenceQuery<TSequence> GetAll<TSequence, TKey>(this IBaseIndex<TSequence, TKey> index, params TKey[] keys)
{
return target.GetAll(key, index.Name);
return index.Table.GetAll(keys: keys, indexName: index.Name);
}

public static ISequenceQuery<T> Filter<T>(this ISequenceQuery<T> target, Expression<Func<T, bool>> filterExpression)
Expand Down Expand Up @@ -174,7 +194,7 @@ public static ISequenceQuery<TSequence> Between<TSequence, TKey>(this ISequenceQ
return new BetweenQuery<TSequence, TKey>(target, leftKey, rightKey, indexName, leftBound, rightBound);
}

public static ISequenceQuery<TSequence> Between<TSequence, TKey>(this ISequenceQuery<TSequence> target, TKey leftKey, TKey rightKey, IIndex<TSequence, TKey> index, Bound leftBound = Bound.Closed, Bound rightBound = Bound.Open)
public static ISequenceQuery<TSequence> Between<TSequence, TKey>(this ISequenceQuery<TSequence> target, TKey leftKey, TKey rightKey, IBaseIndex<TSequence, TKey> index, Bound leftBound = Bound.Closed, Bound rightBound = Bound.Open)
{
return target.Between(leftKey, rightKey, index.Name, leftBound, rightBound);
}
Expand Down Expand Up @@ -331,7 +351,7 @@ public static ISequenceQuery<Tuple<TLeft, TRight>> EqJoin<TLeft, TRight, TIndexT
this ISequenceQuery<TLeft> leftQuery,
Expression<Func<TLeft, object>> leftMemberReferenceExpression,
ISequenceQuery<TRight> rightQuery,
IIndex<TRight, TIndexType> index)
IBaseIndex<TRight, TIndexType> index)
{
return leftQuery.EqJoin(leftMemberReferenceExpression, rightQuery, index.Name);
}
Expand Down
19 changes: 12 additions & 7 deletions rethinkdb-net/QueryTerm/GetAllQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ namespace RethinkDb.QueryTerm
public class GetAllQuery<TSequence, TKey> : ISequenceQuery<TSequence>
{
private readonly ISequenceQuery<TSequence> tableTerm;
private readonly TKey key;
private readonly TKey[] keys;
private readonly string indexName;

public GetAllQuery(ISequenceQuery<TSequence> tableTerm, TKey key, string indexName)
public GetAllQuery(ISequenceQuery<TSequence> tableTerm, TKey[] keys, string indexName)
{
this.tableTerm = tableTerm;
this.key = key;
this.keys = keys;
this.indexName = indexName;
}

Expand All @@ -24,10 +24,15 @@ public Term GenerateTerm(IDatumConverterFactory datumConverterFactory)
type = Term.TermType.GET_ALL,
};
getAllTerm.args.Add(tableTerm.GenerateTerm(datumConverterFactory));
getAllTerm.args.Add(new Term() {
type = Term.TermType.DATUM,
datum = datumConverterFactory.Get<TKey>().ConvertObject(key)
});
var datumConverter = datumConverterFactory.Get<TKey>();
foreach (var key in keys)
{
getAllTerm.args.Add(new Term()
{
type = Term.TermType.DATUM,
datum = datumConverter.ConvertObject(key)
});
}
if (!String.IsNullOrEmpty(indexName))
{
getAllTerm.optargs.Add(new Term.AssocPair() {
Expand Down
4 changes: 2 additions & 2 deletions rethinkdb-net/QueryTerm/IndexCreateQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class IndexCreateQuery<TTable, TIndexExpression> : IWriteQuery<DmlRespons
private readonly Expression<Func<TTable, TIndexExpression>> indexExpression;
private readonly bool multiIndex;

public IndexCreateQuery( ITableQuery<TTable> tableTerm, string indexName, Expression<Func<TTable, TIndexExpression>> indexExpression, bool multiIndex )
public IndexCreateQuery(ITableQuery<TTable> tableTerm, string indexName, Expression<Func<TTable, TIndexExpression>> indexExpression, bool multiIndex)
{
this.tableTerm = tableTerm;
this.indexName = indexName;
Expand All @@ -34,7 +34,7 @@ public Term GenerateTerm(IDatumConverterFactory datumConverterFactory)
},
});
indexCreate.args.Add(ExpressionUtils.CreateFunctionTerm(datumConverterFactory, indexExpression));
if( multiIndex )
if (multiIndex)
{
indexCreate.optargs.Add( new Term.AssocPair
{
Expand Down
5 changes: 4 additions & 1 deletion rethinkdb-net/rethinkdb-net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,11 @@
<Compile Include="UngroupObject.cs" />
<Compile Include="QueryTerm\MapGroupQuery.cs" />
<Compile Include="QueryTerm\ReduceGroupQuery.cs" />
<Compile Include="Index.cs" />
<Compile Include="Interfaces\IMultiIndex.cs" />
<Compile Include="MultiIndex.cs" />
<Compile Include="Interfaces\IBaseIndex.cs" />
<Compile Include="Interfaces\IIndex.cs" />
<Compile Include="Index.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down

0 comments on commit e501f46

Please sign in to comment.