Skip to content

Commit

Permalink
Merge pull request #235 from mfenniak/compound_indexes
Browse files Browse the repository at this point in the history
Implemented Compound Indexes
  • Loading branch information
mfenniak committed Oct 4, 2015
2 parents 7257e12 + 80cedc1 commit 87ffe57
Show file tree
Hide file tree
Showing 12 changed files with 512 additions and 1 deletion.
2 changes: 2 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Features

* Compound secondary indexes are now supported the IndexDefine API. This allows you to create a .NET object that represents a RethinkDB index over multiple columns (using ```table.IndexDefine("name", obj => obj.FirstField, obj => obj.SecondField)```), which can then be used to create the index (```conn.Run(index.IndexCreate())```), and query the index (```conn.Run(index.GetAll(index.Key("first field type", 123)))```). Thanks to @nkreipke for the patch. [PR #229](https://github.com/mfenniak/rethinkdb-net/pull/229) / [PR #235](https://github.com/mfenniak/rethinkdb-net/pull/235)

* Added working Reset function to all query enumerators to reissue the query from the beginning. [Issues #148](https://github.com/mfenniak/rethinkdb-net/issues/148)

* Added IsEmpty query; ```query.IsEmpty()``` will return true or false if the query has records. Thanks to @nkreipke for the patch. [PR #226](https://github.com/mfenniak/rethinkdb-net/pull/226) / [PR #231](https://github.com/mfenniak/rethinkdb-net/pull/231)
Expand Down
1 change: 1 addition & 0 deletions rethinkdb-net-newtonsoft/Configuration/NewtonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public NewtonSerializer() : base(
BoundEnumDatumConverterFactory.Instance,
NullableDatumConverterFactory.Instance,
NamedValueDictionaryDatumConverterFactory.Instance,
CompoundIndexDatumConverterFactory.Instance,
NewtonsoftDatumConverterFactory.Instance
)
{
Expand Down
20 changes: 20 additions & 0 deletions rethinkdb-net-test/Integration/TableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -541,5 +541,25 @@ public void NullableHasValueFilter()
}
count.Should().Be(1);
}

[Test]
public void CreateCompoundIndexStronglyTyped()
{
var index = testTable.IndexDefine("Compound", a => a.Name, a => a.SomeNumber);
connection.Run(index.IndexCreate());

var resp = connection.Run(testTable.Insert(new TestObject[] {
new TestObject() { Name = "1", SomeNumber = 1 },
new TestObject() { Name = "2", SomeNumber = 2 },
new TestObject() { Name = "3", SomeNumber = 3 },
}));
Assert.That(resp, Is.Not.Null);

connection.Run(index.IndexWait()).ToArray(); // ToArray ensures that the IEnumerable is actually evaluated completely and the wait is completed

var results = connection.Run(index.GetAll(index.Key("1", 1)));

results.Should().HaveCount(1);
}
}
}
127 changes: 127 additions & 0 deletions rethinkdb-net/CompoundIndex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Net;

namespace RethinkDb
{
public class CompoundIndexBase<TRecord>
{
private readonly ITableQuery<TRecord> table;
private readonly string name;
private readonly Expression[] indexExpressions;

protected CompoundIndexBase(ITableQuery<TRecord> table, string name, Expression[] indexExpressions)
{
this.table = table;
this.name = name;
this.indexExpressions = indexExpressions;
}

public Expression[] IndexAccessor
{
get { return indexExpressions; }
}

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

public string Name
{
get { return name; }
}
}

public class CompoundIndex<TRecord, TKey1, TKey2> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2)
: base(table, name, new Expression[] { indexExpression1, indexExpression2 })
{
}

public CompoundIndexKey<TKey1, TKey2> Key(TKey1 key1, TKey2 key2)
{
return new CompoundIndexKey<TKey1, TKey2>(key1, key2);
}
}

public class CompoundIndex<TRecord, TKey1, TKey2, TKey3> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2, TKey3>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2, Expression<Func<TRecord, TKey3>> indexExpression3)
: base(table, name, new Expression[] { indexExpression1, indexExpression2, indexExpression3 })
{
}

public CompoundIndexKey<TKey1, TKey2, TKey3> Key(TKey1 key1, TKey2 key2, TKey3 key3)
{
return new CompoundIndexKey<TKey1, TKey2, TKey3>(key1, key2, key3);
}
}

public class CompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2, Expression<Func<TRecord, TKey3>> indexExpression3, Expression<Func<TRecord, TKey4>> indexExpression4)
: base(table, name, new Expression[] { indexExpression1, indexExpression2, indexExpression3, indexExpression4 })
{
}

public CompoundIndexKey<TKey1, TKey2, TKey3, TKey4> Key(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4)
{
return new CompoundIndexKey<TKey1, TKey2, TKey3, TKey4>(key1, key2, key3, key4);
}
}

public class CompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2, Expression<Func<TRecord, TKey3>> indexExpression3, Expression<Func<TRecord, TKey4>> indexExpression4, Expression<Func<TRecord, TKey5>> indexExpression5)
: base(table, name, new Expression[] { indexExpression1, indexExpression2, indexExpression3, indexExpression4, indexExpression5 })
{
}

public CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5> Key(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5)
{
return new CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5>(key1, key2, key3, key4, key5);
}
}

public class CompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5, TKey6> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5, TKey6>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2, Expression<Func<TRecord, TKey3>> indexExpression3, Expression<Func<TRecord, TKey4>> indexExpression4, Expression<Func<TRecord, TKey5>> indexExpression5, Expression<Func<TRecord, TKey6>> indexExpression6)
: base(table, name, new Expression[] { indexExpression1, indexExpression2, indexExpression3, indexExpression4, indexExpression5, indexExpression6 })
{
}

public CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6> Key(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5, TKey6 key6)
{
return new CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6>(key1, key2, key3, key4, key5, key6);
}
}

public class CompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2, Expression<Func<TRecord, TKey3>> indexExpression3, Expression<Func<TRecord, TKey4>> indexExpression4, Expression<Func<TRecord, TKey5>> indexExpression5, Expression<Func<TRecord, TKey6>> indexExpression6, Expression<Func<TRecord, TKey7>> indexExpression7)
: base(table, name, new Expression[] { indexExpression1, indexExpression2, indexExpression3, indexExpression4, indexExpression5, indexExpression6, indexExpression7 })
{
}

public CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7> Key(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5, TKey6 key6, TKey7 key7)
{
return new CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7>(key1, key2, key3, key4, key5, key6, key7);
}
}

public class CompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7, TKey8> : CompoundIndexBase<TRecord>, ICompoundIndex<TRecord, TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7, TKey8>
{
public CompoundIndex(ITableQuery<TRecord> table, string name, Expression<Func<TRecord, TKey1>> indexExpression1, Expression<Func<TRecord, TKey2>> indexExpression2, Expression<Func<TRecord, TKey3>> indexExpression3, Expression<Func<TRecord, TKey4>> indexExpression4, Expression<Func<TRecord, TKey5>> indexExpression5, Expression<Func<TRecord, TKey6>> indexExpression6, Expression<Func<TRecord, TKey7>> indexExpression7, Expression<Func<TRecord, TKey8>> indexExpression8)
: base(table, name, new Expression[] { indexExpression1, indexExpression2, indexExpression3, indexExpression4, indexExpression5, indexExpression6, indexExpression7, indexExpression8 })
{
}

public CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7, TKey8> Key(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5, TKey6 key6, TKey7 key7, TKey8 key8)
{
return new CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7, TKey8>(key1, key2, key3, key4, key5, key6, key7, key8);
}
}
}
78 changes: 78 additions & 0 deletions rethinkdb-net/CompoundIndexKeys.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RethinkDb
{
public class CompoundIndexKey
{
protected CompoundIndexKey(params object[] keyValues)
{
this.KeyValues = keyValues;
}

public object[] KeyValues
{
get;
set;
}
}

public class CompoundIndexKey<TKey1, TKey2> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2)
: base(key1, key2)
{
}
}

public class CompoundIndexKey<TKey1, TKey2, TKey3> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2, TKey3 key3)
: base(key1, key2, key3)
{
}
}

public class CompoundIndexKey<TKey1, TKey2, TKey3, TKey4> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4)
: base(key1, key2, key3, key4)
{
}
}

public class CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5)
: base(key1, key2, key3, key4, key5)
{
}
}

public class CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5, TKey6 key6)
: base(key1, key2, key3, key4, key5, key6)
{
}
}

public class CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5, TKey6 key6, TKey7 key7)
: base(key1, key2, key3, key4, key5, key6, key7)
{
}
}

public class CompoundIndexKey<TKey1, TKey2, TKey3, TKey4, TKey5, TKey6, TKey7, TKey8> : CompoundIndexKey
{
public CompoundIndexKey(TKey1 key1, TKey2 key2, TKey3 key3, TKey4 key4, TKey5 key5, TKey6 key6, TKey7 key7, TKey8 key8)
: base(key1, key2, key3, key4, key5, key6, key7, key8)
{
}
}
}
3 changes: 2 additions & 1 deletion rethinkdb-net/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public Connection()
TimeSpanDatumConverterFactory.Instance,
GroupingDictionaryDatumConverterFactory.Instance,
ObjectDatumConverterFactory.Instance,
NamedValueDictionaryDatumConverterFactory.Instance
NamedValueDictionaryDatumConverterFactory.Instance,
CompoundIndexDatumConverterFactory.Instance
),
new Expressions.DefaultExpressionConverterFactory()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RethinkDb.Spec;

namespace RethinkDb.DatumConverters
{
public class CompoundIndexDatumConverterFactory : AbstractDatumConverterFactory
{
public static readonly CompoundIndexDatumConverterFactory Instance = new CompoundIndexDatumConverterFactory();

public override bool TryGet<T>(IDatumConverterFactory rootDatumConverterFactory, out IDatumConverter<T> datumConverter)
{
if (rootDatumConverterFactory == null)
throw new ArgumentNullException("rootDatumConverterFactory");

datumConverter = null;

if (typeof(CompoundIndexKey).IsAssignableFrom(typeof(T)))
{
var retval = Activator.CreateInstance(
typeof(CompoundIndexKeyDatumConverterShim<>).MakeGenericType(typeof(T)),
new object[] { rootDatumConverterFactory }
);
datumConverter = (IDatumConverter<T>)retval;
}

return datumConverter != null;
}

public class CompoundIndexKeyDatumConverterShim<T> : AbstractReferenceTypeDatumConverter<T>
where T : CompoundIndexKey
{
private readonly CompoundIndexKeyDatumConverter datumConverter;

public CompoundIndexKeyDatumConverterShim(IDatumConverterFactory rootDatumConverterFactory)
{
this.datumConverter = new CompoundIndexKeyDatumConverter(rootDatumConverterFactory);
}

#region implemented abstract members of AbstractReferenceTypeDatumConverter

public override T ConvertDatum(Datum datum)
{
throw new NotSupportedException("Converting back to a CompoundIndexKey object is not supported.");
}

public override Datum ConvertObject(T value)
{
return datumConverter.ConvertObject(value);
}

#endregion
}

public class CompoundIndexKeyDatumConverter : AbstractReferenceTypeDatumConverter<CompoundIndexKey>
{
private readonly IDatumConverterFactory rootDatumConverterFactory;

public CompoundIndexKeyDatumConverter(IDatumConverterFactory rootDatumConverterFactory)
{
this.rootDatumConverterFactory = rootDatumConverterFactory;
}

public override CompoundIndexKey ConvertDatum(Datum datum)
{
throw new NotSupportedException("Converting back to a CompoundIndexKey object is not supported.");
}

public override Datum ConvertObject(CompoundIndexKey compoundIndexKey)
{
if (compoundIndexKey == null)
return new Datum { type = Datum.DatumType.R_NULL };

var retval = new Datum {type = Datum.DatumType.R_ARRAY};
foreach (var key in compoundIndexKey.KeyValues)
{
var converter = rootDatumConverterFactory.Get(key.GetType());
retval.r_array.Add(converter.ConvertObject(key));
}

return retval;
}
}
}
}
11 changes: 11 additions & 0 deletions rethinkdb-net/Expressions/BaseExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ protected Term SimpleMap(IDatumConverterFactory datumConverterFactory, Expressio
return AttemptClientSideConversion(datumConverterFactory, expr);
}

case ExpressionType.NewArrayInit:
var arrayExpression = (NewArrayExpression)expr;
var array = new Term {type = Term.TermType.MAKE_ARRAY};

foreach (var expression in arrayExpression.Expressions)
{
array.args.Add(RecursiveMap(expression));
}

return array;

case ExpressionType.Call:
{
var callExpression = (MethodCallExpression)expr;
Expand Down
Loading

0 comments on commit 87ffe57

Please sign in to comment.