You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2017/07/04 11:51:34 UTC
[2/3] ignite git commit: IGNITE-5532 .NET: Split CacheLinqTest into
partial classes
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSimpleName.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSimpleName.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSimpleName.cs
deleted file mode 100644
index 9743e60..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSimpleName.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace Apache.Ignite.Core.Tests.Cache.Query
-{
- using Apache.Ignite.Core.Binary;
- using NUnit.Framework;
-
- /// <summary>
- /// LINQ test with simple name mapper.
- /// </summary>
- [TestFixture]
- public class CacheLinqTestSimpleName : CacheLinqTest
- {
- /** <inheritdoc /> */
- protected override IBinaryNameMapper GetNameMapper()
- {
- return BinaryBasicNameMapper.SimpleNameInstance;
- }
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs
deleted file mode 100644
index 7473be9..0000000
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/CacheLinqTestSqlEscapeAll.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace Apache.Ignite.Core.Tests.Cache.Query
-{
- using NUnit.Framework;
-
- /// <summary>
- /// LINQ test with simple name mapper.
- /// </summary>
- [TestFixture]
- public class CacheLinqTestSqlEscapeAll : CacheLinqTest
- {
- /** <inheritdoc /> */
- protected override bool GetSqlEscapeAll()
- {
- return true;
- }
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Aggregates.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Aggregates.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Aggregates.cs
new file mode 100644
index 0000000..b6bbb67
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Aggregates.cs
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Linq;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests aggregates.
+ /// </summary>
+ [Test]
+ public void TestAggregates()
+ {
+ var cache = GetPersonCache().AsCacheQueryable();
+
+ Assert.AreEqual(PersonCount, cache.Count());
+ Assert.AreEqual(PersonCount, cache.Select(x => x.Key).Count());
+ Assert.AreEqual(2, cache.Select(x => x.Value.OrganizationId).Distinct().Count());
+
+ // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
+ Assert.Throws<NotSupportedException>(() => cache.Select(x => new { x.Key, x.Value }).Count());
+
+ // Min/max/sum/avg
+ var ints = cache.Select(x => x.Key);
+ Assert.AreEqual(0, ints.Min());
+ Assert.AreEqual(PersonCount - 1, ints.Max());
+ Assert.AreEqual(ints.ToArray().Sum(), ints.Sum());
+ Assert.AreEqual((int)ints.ToArray().Average(), (int)ints.Average());
+
+ var dupInts = ints.Select(x => x / 10); // duplicate values
+ CollectionAssert.AreEquivalent(dupInts.ToArray().Distinct().ToArray(), dupInts.Distinct().ToArray());
+ Assert.AreEqual(dupInts.ToArray().Distinct().Sum(), dupInts.Distinct().Sum());
+
+ // All/any
+ Assert.IsFalse(ints.Where(x => x > -5).Any(x => x > PersonCount && x > 0));
+ Assert.IsTrue(ints.Any(x => x < PersonCount / 2));
+
+ // Skip/take
+ var keys = cache.Select(x => x.Key).OrderBy(x => x);
+ Assert.AreEqual(new[] { 0, 1 }, keys.Take(2).ToArray());
+ Assert.AreEqual(new[] { 1, 2 }, keys.Skip(1).Take(2).ToArray());
+ Assert.AreEqual(new[] { PersonCount - 2, PersonCount - 1 }, keys.Skip(PersonCount - 2).ToArray());
+ }
+
+ /// <summary>
+ /// Tests aggregates with all clause.
+ /// </summary>
+ [Test]
+ public void TestAggregatesAll()
+ {
+ var ints = GetPersonCache().AsCacheQueryable().Select(x => x.Key);
+
+ // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
+ var ex = Assert.Throws<NotSupportedException>(() => ints.Where(x => x > -10)
+ .All(x => x < PersonCount && x >= 0));
+
+ Assert.IsTrue(ex.Message.StartsWith("Operator is not supported: All"));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Base.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Base.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Base.cs
new file mode 100644
index 0000000..ae9fd5f
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Base.cs
@@ -0,0 +1,506 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Collections;
+ using System.Linq;
+ using System.Linq.Expressions;
+ using System.Threading;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Core.Cache;
+ using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /** Cache name. */
+ private const string PersonOrgCacheName = "person_org";
+
+ /** Cache name. */
+ private const string PersonSecondCacheName = "person_cache";
+
+ /** Role cache name. */
+ private const string RoleCacheName = "role_cache";
+
+ /** */
+ private const int RoleCount = 3;
+
+ /** */
+ private const int PersonCount = 900;
+
+ /** */
+ private bool _runDbConsole;
+
+ /** */
+ private static readonly DateTime StartDateTime = new DateTime(2000, 5, 17, 15, 4, 5, DateTimeKind.Utc);
+
+ /// <summary>
+ /// Fixture set up.
+ /// </summary>
+ [TestFixtureSetUp]
+ public void FixtureSetUp()
+ {
+ _runDbConsole = false; // set to true to open H2 console
+
+ if (_runDbConsole)
+ Environment.SetEnvironmentVariable("IGNITE_H2_DEBUG_CONSOLE", "true");
+
+ Ignition.Start(GetConfig());
+ Ignition.Start(GetConfig("grid2"));
+
+ // Populate caches
+ var cache = GetPersonCache();
+ var personCache = GetSecondPersonCache();
+
+ for (var i = 0; i < PersonCount; i++)
+ {
+ cache.Put(i, new Person(i, string.Format(" Person_{0} ", i))
+ {
+ Address = new Address {Zip = i, Street = "Street " + i, AliasTest = i},
+ OrganizationId = i%2 + 1000,
+ Birthday = StartDateTime.AddYears(i),
+ AliasTest = -i
+ });
+
+ var i2 = i + PersonCount;
+ personCache.Put(i2, new Person(i2, "Person_" + i2)
+ {
+ Address = new Address {Zip = i2, Street = "Street " + i2},
+ OrganizationId = i%2 + 1000,
+ Birthday = StartDateTime.AddYears(i)
+ });
+ }
+
+ var orgCache = GetOrgCache();
+
+ orgCache[1000] = new Organization {Id = 1000, Name = "Org_0"};
+ orgCache[1001] = new Organization {Id = 1001, Name = "Org_1"};
+ orgCache[1002] = new Organization {Id = 1002, Name = null};
+
+ var roleCache = GetRoleCache();
+
+ roleCache[new RoleKey(1, 101)] = new Role {Name = "Role_1", Date = StartDateTime};
+ roleCache[new RoleKey(2, 102)] = new Role {Name = "Role_2", Date = StartDateTime.AddYears(1)};
+ roleCache[new RoleKey(3, 103)] = new Role {Name = null, Date = StartDateTime.AddHours(5432)};
+ }
+
+ /// <summary>
+ /// Gets the configuration.
+ /// </summary>
+ private IgniteConfiguration GetConfig(string gridName = null)
+ {
+ return new IgniteConfiguration(TestUtils.GetTestConfiguration())
+ {
+ BinaryConfiguration = new BinaryConfiguration(typeof(Person),
+ typeof(Organization), typeof(Address), typeof(Role), typeof(RoleKey), typeof(Numerics))
+ {
+ NameMapper = GetNameMapper()
+ },
+ IgniteInstanceName = gridName
+ };
+ }
+
+ /// <summary>
+ /// Gets the name mapper.
+ /// </summary>
+ protected virtual IBinaryNameMapper GetNameMapper()
+ {
+ return BinaryBasicNameMapper.FullNameInstance;
+ }
+
+ /// <summary>
+ /// Gets the SqlEscapeAll setting.
+ /// </summary>
+ protected virtual bool GetSqlEscapeAll()
+ {
+ return false;
+ }
+
+ /// <summary>
+ /// Fixture tear down.
+ /// </summary>
+ [TestFixtureTearDown]
+ public void FixtureTearDown()
+ {
+ if (_runDbConsole)
+ Thread.Sleep(Timeout.Infinite);
+ Ignition.StopAll(true);
+ }
+
+ /// <summary>
+ /// Gets the person cache.
+ /// </summary>
+ /// <returns></returns>
+ private ICache<int, Person> GetPersonCache()
+ {
+ return GetCacheOf<Person>();
+ }
+
+ /// <summary>
+ /// Gets the org cache.
+ /// </summary>
+ /// <returns></returns>
+ private ICache<int, Organization> GetOrgCache()
+ {
+ return GetCacheOf<Organization>();
+ }
+
+ /// <summary>
+ /// Gets the cache.
+ /// </summary>
+ private ICache<int, T> GetCacheOf<T>()
+ {
+ return Ignition.GetIgnite()
+ .GetOrCreateCache<int, T>(new CacheConfiguration(PersonOrgCacheName,
+ new QueryEntity(typeof (int), typeof (Person))
+ {
+ Aliases = new[]
+ {
+ new QueryAlias("AliasTest", "Person_AliasTest"),
+ new QueryAlias("Address.AliasTest", "Addr_AliasTest")
+ },
+ KeyFieldName = "MyKey",
+ ValueFieldName = "MyValue",
+ Fields =
+ {
+ new QueryField("MyKey", typeof(int)),
+ new QueryField("MyValue", typeof(T)),
+ }
+ },
+ new QueryEntity(typeof (int), typeof (Organization)))
+ {
+ CacheMode = CacheMode.Replicated,
+ SqlEscapeAll = GetSqlEscapeAll()
+ });
+ }
+
+ /// <summary>
+ /// Gets the role cache.
+ /// </summary>
+ private ICache<RoleKey, Role> GetRoleCache()
+ {
+ return Ignition.GetIgnite()
+ .GetOrCreateCache<RoleKey, Role>(new CacheConfiguration(RoleCacheName,
+ new QueryEntity(typeof (RoleKey), typeof (Role)))
+ {
+ CacheMode = CacheMode.Replicated,
+ SqlEscapeAll = GetSqlEscapeAll()
+ });
+ }
+
+ /// <summary>
+ /// Gets the second person cache.
+ /// </summary>
+ private ICache<int, Person> GetSecondPersonCache()
+ {
+ return Ignition.GetIgnite()
+ .GetOrCreateCache<int, Person>(
+ new CacheConfiguration(PersonSecondCacheName,
+ new QueryEntity(typeof(int), typeof(Person))
+ {
+ TableName = "CustomPersons"
+ })
+ {
+ CacheMode = CacheMode.Replicated,
+ SqlEscapeAll = GetSqlEscapeAll()
+ });
+ }
+
+ /// <summary>
+ /// Checks that function maps to SQL function properly.
+ /// </summary>
+ private static void CheckFunc<T, TR>(Expression<Func<T, TR>> exp, IQueryable<T> query,
+ Func<TR, TR> localResultFunc = null)
+ {
+ localResultFunc = localResultFunc ?? (x => x);
+
+ // Calculate result locally, using real method invocation
+ var expected = query.ToArray().AsQueryable().Select(exp).Select(localResultFunc).OrderBy(x => x).ToArray();
+
+ // Perform SQL query
+ var actual = query.Select(exp).ToArray().OrderBy(x => x).ToArray();
+
+ // Compare results
+ CollectionAssert.AreEqual(expected, actual, new NumericComparer());
+
+ // Perform intermediate anonymous type conversion to check type projection
+ actual = query.Select(exp).Select(x => new {Foo = x}).ToArray().Select(x => x.Foo)
+ .OrderBy(x => x).ToArray();
+
+ // Compare results
+ CollectionAssert.AreEqual(expected, actual, new NumericComparer());
+ }
+
+ /// <summary>
+ /// Checks that function used in Where Clause maps to SQL function properly
+ /// </summary>
+ private static void CheckWhereFunc<TKey, TEntry>(IQueryable<ICacheEntry<TKey,TEntry>> query,
+ Expression<Func<ICacheEntry<TKey, TEntry>,bool>> whereExpression)
+ {
+ // Calculate result locally, using real method invocation
+ var expected = query
+ .ToArray()
+ .AsQueryable()
+ .Where(whereExpression)
+ .Select(entry => entry.Key)
+ .OrderBy(x => x)
+ .ToArray();
+
+ // Perform SQL query
+ var actual = query
+ .Where(whereExpression)
+ .Select(entry => entry.Key)
+ .ToArray()
+ .OrderBy(x => x)
+ .ToArray();
+
+ // Compare results
+ CollectionAssert.AreEqual(expected, actual, new NumericComparer());
+ }
+
+ /// <summary>
+ /// Tests conditinal statement
+ /// </summary>
+ private void TestConditional<T>(T even , T odd, Func<T,T,bool> comparer = null)
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+
+ var res = persons
+ .Select(x => new {Foo = x.Key % 2 == 0 ? even : odd, x.Value})
+ .ToArray();
+
+ if (comparer != null)
+ {
+ Assert.IsTrue(comparer(even, res[0].Foo));
+ Assert.IsTrue(comparer(odd, res[1].Foo));
+ }
+ else
+ {
+ Assert.AreEqual(even, res[0].Foo);
+ Assert.AreEqual(odd, res[1].Foo);
+ }
+ }
+
+ /// <summary>
+ /// Tests conditinal statement for structs with default and null values
+ /// </summary>
+ private void TestConditionalWithNullableStructs<T>(T? defaultFalue = null) where T : struct
+ {
+ var def = defaultFalue ?? default(T);
+ TestConditional(def, (T?) null);
+ }
+
+ public interface IPerson
+ {
+ int Age { get; set; }
+ string Name { get; set; }
+ }
+
+ public class Person : IBinarizable, IPerson
+ {
+ public Person(int age, string name)
+ {
+ Age = age;
+ Name = name;
+ }
+
+ [QuerySqlField(Name = "age1")] public int Age { get; set; }
+
+ [QuerySqlField] public string Name { get; set; }
+
+ [QuerySqlField] public Address Address { get; set; }
+
+ [QuerySqlField] public int OrganizationId { get; set; }
+
+ [QuerySqlField] public DateTime? Birthday { get; set; }
+
+ [QuerySqlField] public int AliasTest { get; set; }
+
+ public void WriteBinary(IBinaryWriter writer)
+ {
+ writer.WriteInt("age1", Age);
+ writer.WriteString("name", Name);
+ writer.WriteInt("OrganizationId", OrganizationId);
+ writer.WriteObject("Address", Address);
+ writer.WriteTimestamp("Birthday", Birthday);
+ writer.WriteInt("AliasTest", AliasTest);
+ }
+
+ public void ReadBinary(IBinaryReader reader)
+ {
+ Age = reader.ReadInt("age1");
+ Name = reader.ReadString("name");
+ OrganizationId = reader.ReadInt("OrganizationId");
+ Address = reader.ReadObject<Address>("Address");
+ Birthday = reader.ReadTimestamp("Birthday");
+ AliasTest = reader.ReadInt("AliasTest");
+ }
+ }
+
+ public class Address
+ {
+ [QuerySqlField] public int Zip { get; set; }
+ [QuerySqlField] public string Street { get; set; }
+ [QuerySqlField] public int AliasTest { get; set; }
+ }
+
+ public class Organization
+ {
+ [QuerySqlField] public int Id { get; set; }
+ [QuerySqlField] public string Name { get; set; }
+ }
+
+ public interface IRole
+ {
+ string Name { get; }
+ DateTime Date { get; }
+ }
+
+ public class Role : IRole
+ {
+ [QuerySqlField] public string Name { get; set; }
+ [QuerySqlField] public DateTime Date { get; set; }
+ }
+
+ public class Numerics
+ {
+ public Numerics(double val)
+ {
+ Double = val;
+ Float = (float) val;
+ Decimal = (decimal) val;
+ Int = (int) val;
+ Uint = (uint) val;
+ Long = (long) val;
+ Ulong = (ulong) val;
+ Short = (short) val;
+ Ushort = (ushort) val;
+ Byte = (byte) val;
+ Sbyte = (sbyte) val;
+ }
+
+ [QuerySqlField] public double Double { get; set; }
+ [QuerySqlField] public float Float { get; set; }
+ [QuerySqlField] public decimal Decimal { get; set; }
+ [QuerySqlField] public int Int { get; set; }
+ [QuerySqlField] public uint Uint { get; set; }
+ [QuerySqlField] public long Long { get; set; }
+ [QuerySqlField] public ulong Ulong { get; set; }
+ [QuerySqlField] public short Short { get; set; }
+ [QuerySqlField] public ushort Ushort { get; set; }
+ [QuerySqlField] public byte Byte { get; set; }
+ [QuerySqlField] public sbyte Sbyte { get; set; }
+ }
+
+ public struct RoleKey : IEquatable<RoleKey>
+ {
+ private readonly int _foo;
+ private readonly long _bar;
+
+ public RoleKey(int foo, long bar)
+ {
+ _foo = foo;
+ _bar = bar;
+ }
+
+ [QuerySqlField(Name = "_foo")]
+ public int Foo
+ {
+ get { return _foo; }
+ }
+
+ [QuerySqlField(Name = "_bar")]
+ public long Bar
+ {
+ get { return _bar; }
+ }
+
+ public bool Equals(RoleKey other)
+ {
+ return _foo == other._foo && _bar == other._bar;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ return obj is RoleKey && Equals((RoleKey) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (_foo*397) ^ _bar.GetHashCode();
+ }
+ }
+
+ public static bool operator ==(RoleKey left, RoleKey right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(RoleKey left, RoleKey right)
+ {
+ return !left.Equals(right);
+ }
+ }
+
+ /// <summary>
+ /// Epsilon comparer.
+ /// </summary>
+ private class NumericComparer : IComparer
+ {
+ /** <inheritdoc /> */
+ public int Compare(object x, object y)
+ {
+ if (Equals(x, y))
+ return 0;
+
+ if (x is double)
+ {
+ var dx = (double) x;
+ var dy = (double) y;
+
+ // Epsilon is proportional to the min value, but not too small.
+ const double epsilon = 2E-10d;
+ var min = Math.Min(Math.Abs(dx), Math.Abs(dy));
+ var relEpsilon = Math.Max(min*epsilon, epsilon);
+
+ // Compare with epsilon because some funcs return slightly different results.
+ return Math.Abs((double) x - (double) y) < relEpsilon ? 0 : 1;
+ }
+
+ return ((IComparable) x).CompareTo(y);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.CompiledQuery.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.CompiledQuery.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.CompiledQuery.cs
new file mode 100644
index 0000000..1cd377e
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.CompiledQuery.cs
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System.Linq;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests the compiled query with various constructs.
+ /// </summary>
+ [Test]
+ public void TestCompiledQuery()
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+ var roles = GetRoleCache().AsCacheQueryable();
+
+ // Embedded args
+ var qry0 = CompiledQuery.Compile(() => persons.Where(x => x.Key < 3 && x.Value.Name.Contains("son")));
+ Assert.AreEqual(3, qry0().Count());
+
+ // Lambda args
+ var qry1 = CompiledQuery.Compile((int minKey, int take, int skip) => persons.Where(x => x.Key > minKey)
+ .Take(take).Skip(skip));
+ Assert.AreEqual(3, qry1(-1, 3, 1).GetAll().Count);
+
+ qry1 = CompiledQuery.Compile((int skip, int take, int minKey) => persons.Where(x => x.Key > minKey)
+ .Take(take).Skip(skip));
+
+ Assert.AreEqual(5, qry1(2, 5, 20).GetAll().Count);
+
+ // Mixed args
+ var qry2 = CompiledQuery.Compile((int maxKey, int minKey) =>
+ persons.Where(x => x.Key < maxKey
+ && x.Value.Name.Contains("er")
+ && x.Value.Age < maxKey
+ && x.Key > minKey).Skip(2));
+
+ Assert.AreEqual(6, qry2(10, 1).Count());
+
+ // Join
+ var qry3 = CompiledQuery.Compile(() =>
+ roles.Join(persons, r => r.Key.Foo, p => p.Key, (r, p) => r.Value.Name));
+
+ Assert.AreEqual(RoleCount, qry3().Count());
+
+ // Join with subquery
+ var qry4 = CompiledQuery.Compile(
+ (int a, int b, string sep) =>
+ roles
+ .Where(x => x.Key.Bar > a)
+ .OrderBy(x => x.Key.Bar)
+ .Join(persons.Where(x => x.Key < b && x.Key > 0),
+ r => r.Key.Foo,
+ p => p.Value.Address.Zip,
+ (r, p) => p.Value.Name + sep + r.Value.Name + "|")
+ .Skip(a).Take(1000)
+ );
+
+ Assert.AreEqual(new[] { " Person_2 =Role_2|", " Person_3 =|" }, qry4(1, PersonCount, "=").ToArray());
+
+ // Union
+ var qry5 = CompiledQuery.Compile(() => roles.Select(x => -x.Key.Foo).Union(persons.Select(x => x.Key)));
+
+ Assert.AreEqual(RoleCount + PersonCount, qry5().Count());
+
+ // Projection
+ var qry6 = CompiledQuery.Compile((int minAge) => persons
+ .Select(x => x.Value)
+ .Where(x => x.Age >= minAge)
+ .Select(x => new { x.Name, x.Age })
+ .OrderBy(x => x.Name));
+
+ var res = qry6(PersonCount - 3).GetAll();
+
+ Assert.AreEqual(3, res.Count);
+ Assert.AreEqual(PersonCount - 3, res[0].Age);
+ }
+
+ /// <summary>
+ /// Tests the compiled query overloads.
+ /// </summary>
+ [Test]
+ public void TestCompiledQueryOverloads()
+ {
+ var cache = GetPersonCache().AsCacheQueryable();
+
+ // const args are allowed
+ Assert.AreEqual(5, CompiledQuery.Compile(() => cache.Where(x => x.Key < 5))().GetAll().Count);
+
+ // 0 arg
+ var qry0 = CompiledQuery.Compile(() => cache.Select(x => x.Value.Name));
+ Assert.AreEqual(PersonCount, qry0().ToArray().Length);
+
+ // 1 arg
+ var qry1 = CompiledQuery.Compile((int k) => cache.Where(x => x.Key < k));
+ Assert.AreEqual(3, qry1(3).ToArray().Length);
+
+ // 1 arg twice
+ var qry1T = CompiledQuery.Compile((int k) => cache.Where(x => x.Key < k && x.Value.Age < k));
+ Assert.AreEqual(3, qry1T(3).ToArray().Length);
+
+ // 2 arg
+ var qry2 =
+ CompiledQuery.Compile((int i, string s) => cache.Where(x => x.Key < i && x.Value.Name.StartsWith(s)));
+ Assert.AreEqual(5, qry2(5, " Pe").ToArray().Length);
+
+ // Changed param order
+ var qry2R =
+ CompiledQuery.Compile((string s, int i) => cache.Where(x => x.Key < i && x.Value.Name.StartsWith(s)));
+ Assert.AreEqual(5, qry2R(" Pe", 5).ToArray().Length);
+
+ // 3 arg
+ var qry3 = CompiledQuery.Compile((int i, string s, double d) =>
+ cache.Where(x => x.Value.Address.Zip > d && x.Key < i && x.Value.Name.Contains(s)));
+ Assert.AreEqual(5, qry3(5, "son", -10).ToArray().Length);
+
+ // 4 arg
+ var qry4 = CompiledQuery.Compile((int a, int b, int c, int d) =>
+ cache.Select(x => x.Key).Where(k => k > a && k > b && k > c && k < d));
+ Assert.AreEqual(new[] { 3, 4 }, qry4(0, 1, 2, 5).ToArray());
+
+ // 5 arg
+ var qry5 = CompiledQuery.Compile((int a, int b, int c, int d, int e) =>
+ cache.Select(x => x.Key).Where(k => k > a && k > b && k > c && k < d && k < e));
+ Assert.AreEqual(new[] { 3, 4 }, qry5(0, 1, 2, 5, 6).ToArray());
+
+ // 6 arg
+ var qry6 = CompiledQuery.Compile((int a, int b, int c, int d, int e, int f) =>
+ cache.Select(x => x.Key).Where(k => k > a && k > b && k > c && k < d && k < e && k < f));
+ Assert.AreEqual(new[] { 3, 4 }, qry6(0, 1, 2, 5, 6, 7).ToArray());
+
+ // 7 arg
+ var qry7 = CompiledQuery.Compile((int a, int b, int c, int d, int e, int f, int g) =>
+ cache.Select(x => x.Key).Where(k => k > a && k > b && k > c && k < d && k < e && k < f && k < g));
+ Assert.AreEqual(new[] { 3, 4 }, qry7(0, 1, 2, 5, 6, 7, 8).ToArray());
+
+ // 8 arg
+ var qry8 = CompiledQuery.Compile((int a, int b, int c, int d, int e, int f, int g, int h) =>
+ cache.Select(x => x.Key)
+ .Where(k => k > a && k > b && k > c && k < d && k < e && k < f && k < g && k < h));
+ Assert.AreEqual(new[] { 3, 4 }, qry8(0, 1, 2, 5, 6, 7, 8, 9).ToArray());
+ }
+
+ /// <summary>
+ /// Tests the free-form compiled query, where user provides an array of arguments.
+ /// </summary>
+ [Test]
+ public void TestCompiledQueryFreeform()
+ {
+ var cache = GetPersonCache().AsCacheQueryable();
+
+ var qry = cache.Where(x => x.Key < 5);
+
+ // Simple
+ var compiled = CompiledQuery.Compile(qry);
+
+ Assert.AreEqual(5, compiled(5).Count());
+ Assert.AreEqual(6, compiled(6).Count());
+
+ // Select
+ var compiledSelect = CompiledQuery.Compile(qry.Select(x => x.Value.Name).OrderBy(x => x));
+
+ Assert.AreEqual(3, compiledSelect(3).Count());
+ Assert.AreEqual(" Person_0 ", compiledSelect(1).Single());
+
+ // Join
+ var compiledJoin = CompiledQuery.Compile(qry.Join(
+ GetOrgCache().AsCacheQueryable().Where(x => x.Value.Name.StartsWith("Org")),
+ p => p.Value.OrganizationId, o => o.Value.Id, (p, o) => o.Key));
+
+ Assert.AreEqual(1000, compiledJoin("Org", 1).Single());
+
+ // Many parameters
+ var qry2 = cache.Where(x => x.Key < 3)
+ .Where(x => x.Key > 0)
+ .Where(x => x.Value.Name.Contains(""))
+ .Where(x => x.Value.Address.Zip > 0)
+ .Where(x => x.Value.Age == 7);
+
+ var compiled2 = CompiledQuery.Compile(qry2);
+
+ Assert.AreEqual(17, compiled2(18, 16, "ers", 13, 17).Single().Key);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Contains.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Contains.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Contains.cs
new file mode 100644
index 0000000..032c746
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Contains.cs
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests IEnumerable.Contains.
+ /// </summary>
+ [Test]
+ public void TestContains()
+ {
+ var cache = GetPersonCache().AsCacheQueryable();
+ var orgCache = GetOrgCache().AsCacheQueryable();
+
+ var keys = new[] { 1, 2, 3 };
+ var emptyKeys = new int[0];
+
+ var bigNumberOfKeys = 10000;
+ var aLotOfKeys = Enumerable.Range(-bigNumberOfKeys + 10 - PersonCount, bigNumberOfKeys + PersonCount)
+ .ToArray();
+ var hashSetKeys = new HashSet<int>(keys);
+ var defferedCollection = Enumerable.Range(1, 10)
+ .Select(i => new { Id = i })
+ .Select(arg => arg.Id);
+
+ CheckWhereFunc(cache, e => new[] { 1, 2, 3 }.Contains(e.Key));
+ CheckWhereFunc(cache, e => emptyKeys.Contains(e.Key));
+ CheckWhereFunc(cache, e => new int[0].Contains(e.Key));
+ CheckWhereFunc(cache, e => new int[0].Contains(e.Key));
+ CheckWhereFunc(cache, e => new List<int> { 1, 2, 3 }.Contains(e.Key));
+ CheckWhereFunc(cache, e => new List<int>(keys).Contains(e.Key));
+ CheckWhereFunc(cache, e => aLotOfKeys.Contains(e.Key));
+ CheckWhereFunc(cache, e => hashSetKeys.Contains(e.Key));
+ CheckWhereFunc(cache, e => !keys.Contains(e.Key));
+ CheckWhereFunc(cache, e => defferedCollection.Contains(e.Key));
+ CheckWhereFunc(orgCache, e => new[] { "Org_1", "NonExistentName", null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => !new[] { "Org_1", "NonExistentName", null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => new[] { "Org_1", null, null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => !new[] { "Org_1", null, null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => new string[] { null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => !new string[] { null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => !new string[] { null, null }.Contains(e.Value.Name));
+ CheckWhereFunc(orgCache, e => new string[] { null, null }.Contains(e.Value.Name));
+
+ //check passing a null object as collection
+ int[] nullKeys = null;
+ var nullKeysEntries = cache
+ .Where(e => nullKeys.Contains(e.Key))
+ .ToArray();
+ Assert.AreEqual(0, nullKeysEntries.Length, "Evaluating 'null.Contains' should return zero results");
+
+
+ Func<int[]> getKeysFunc = () => null;
+ var funcNullKeyEntries = cache
+ .Where(e => getKeysFunc().Contains(e.Key))
+ .ToArray();
+ Assert.AreEqual(0, funcNullKeyEntries.Length, "Evaluating 'null.Contains' should return zero results");
+
+
+ // Check subselect from other cache
+ var subSelectCount = cache
+ .Count(entry => orgCache
+ .Where(orgEntry => orgEntry.Value.Name == "Org_1")
+ .Select(orgEntry => orgEntry.Key)
+ .Contains(entry.Value.OrganizationId));
+ var orgNumberOne = orgCache
+ .Where(orgEntry => orgEntry.Value.Name == "Org_1")
+ .Select(orgEntry => orgEntry.Key)
+ .First();
+ var subSelectCheckCount = cache.Count(entry => entry.Value.OrganizationId == orgNumberOne);
+ Assert.AreEqual(subSelectCheckCount, subSelectCount, "subselecting another CacheQueryable failed");
+
+ var ex = Assert.Throws<NotSupportedException>(() =>
+ CompiledQuery.Compile((int[] k) => cache.Where(x => k.Contains(x.Key))));
+ Assert.AreEqual("'Contains' clause on compiled query parameter is not supported.", ex.Message);
+
+ // check subquery from another cache put in separate variable
+ var orgIds = orgCache
+ .Where(o => o.Value.Name == "Org_1")
+ .Select(o => o.Key);
+
+ var subQueryFromVar = cache
+ .Where(x => orgIds.Contains(x.Value.OrganizationId))
+ .ToArray();
+
+ var subQueryInline = cache
+ .Where(x => orgCache.Where(o => o.Value.Name == "Org_1")
+ .Select(o => o.Key).Contains(x.Value.OrganizationId))
+ .ToArray();
+
+ Assert.AreEqual(subQueryInline.Length, subQueryFromVar.Length);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Custom.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Custom.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Custom.cs
new file mode 100644
index 0000000..f797b4c
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Custom.cs
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Linq;
+ using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Core.Common;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests the RemoveAll extension.
+ /// </summary>
+ [Test]
+ public void TestRemoveAll()
+ {
+ // Use new cache to avoid touching static data.
+ var cache = Ignition.GetIgnite().CreateCache<int, Person>(new CacheConfiguration("deleteAllTest",
+ new QueryEntity(typeof(int), typeof(Person)))
+ {
+ SqlEscapeAll = GetSqlEscapeAll()
+ });
+
+ Enumerable.Range(1, 10).ToList().ForEach(x => cache.Put(x, new Person(x, x.ToString())));
+
+ var queryable = cache.AsCacheQueryable();
+
+ Func<int[]> getKeys = () => cache.Select(x => x.Key).OrderBy(x => x).ToArray();
+
+ // Without predicate.
+ var res = queryable.Where(x => x.Key < 3).RemoveAll();
+ Assert.AreEqual(2, res);
+ Assert.AreEqual(Enumerable.Range(3, 8), getKeys());
+
+ // With predicate.
+ res = queryable.RemoveAll(x => x.Key < 7);
+ Assert.AreEqual(4, res);
+ Assert.AreEqual(Enumerable.Range(7, 4), getKeys());
+
+ // Subquery-style join.
+ var ids = GetPersonCache().AsCacheQueryable().Where(x => x.Key == 7).Select(x => x.Key);
+
+ res = queryable.Where(x => ids.Contains(x.Key)).RemoveAll();
+ Assert.AreEqual(1, res);
+ Assert.AreEqual(Enumerable.Range(8, 3), getKeys());
+
+ // Row number limit.
+ res = queryable.Take(2).RemoveAll();
+ Assert.AreEqual(2, res);
+ Assert.AreEqual(1, getKeys().Length);
+
+ // Unconditional.
+ queryable.RemoveAll();
+ Assert.AreEqual(0, cache.GetSize());
+
+ // Skip is not supported with DELETE.
+ var nex = Assert.Throws<NotSupportedException>(() => queryable.Skip(1).RemoveAll());
+ Assert.AreEqual(
+ "RemoveAll can not be combined with result operators (other than Take): SkipResultOperator",
+ nex.Message);
+
+ // Multiple result operators are not supported with DELETE.
+ nex = Assert.Throws<NotSupportedException>(() => queryable.Skip(1).Take(1).RemoveAll());
+ Assert.AreEqual(
+ "RemoveAll can not be combined with result operators (other than Take): SkipResultOperator, " +
+ "TakeResultOperator, RemoveAllResultOperator", nex.Message);
+
+ // Joins are not supported in H2.
+ var qry = queryable
+ .Where(x => x.Key == 7)
+ .Join(GetPersonCache().AsCacheQueryable(), p => p.Key, p => p.Key, (p1, p2) => p1);
+
+ var ex = Assert.Throws<IgniteException>(() => qry.RemoveAll());
+ Assert.AreEqual("Failed to parse query", ex.Message.Substring(0, 21));
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.DateTime.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.DateTime.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.DateTime.cs
new file mode 100644
index 0000000..b869dc4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.DateTime.cs
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Linq;
+ using Apache.Ignite.Core.Binary;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests date time.
+ /// </summary>
+ [Test]
+ public void TestDateTime()
+ {
+ var roles = GetRoleCache().AsCacheQueryable();
+ var persons = GetPersonCache().AsCacheQueryable();
+
+ // Invalid dateTime
+ // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
+ var ex = Assert.Throws<BinaryObjectException>(() =>
+ roles.Where(x => x.Value.Date > DateTime.Now).ToArray());
+ Assert.AreEqual("DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms.",
+ ex.Message);
+
+ // Test retrieval
+ var dates = roles.OrderBy(x => x.Value.Date).Select(x => x.Value.Date);
+ var expDates = GetRoleCache().Select(x => x.Value.Date).OrderBy(x => x).ToArray();
+ Assert.AreEqual(expDates, dates.ToArray());
+
+ // Filtering
+ Assert.AreEqual(1, persons.Count(x => x.Value.Birthday == StartDateTime));
+ Assert.AreEqual(PersonCount, persons.Count(x => x.Value.Birthday >= StartDateTime));
+ Assert.Greater(persons.Count(x => x.Value.Birthday > DateTime.UtcNow), 1);
+
+ // Joins
+ var join =
+ from role in roles
+ join person in persons on role.Value.Date equals person.Value.Birthday
+ select person;
+
+ Assert.AreEqual(2, join.Count());
+
+ // Functions
+ var strings = dates.Select(x => x.ToString("dd MM YYYY HH:mm:ss")).ToArray();
+ Assert.AreEqual(new[] { "17 05 2000 15:04:05", "29 12 2000 23:04:05", "17 05 2001 15:04:05" }, strings);
+
+ // Properties
+ Assert.AreEqual(new[] { 2000, 2000, 2001 }, dates.Select(x => x.Year).ToArray());
+ Assert.AreEqual(new[] { 5, 12, 5 }, dates.Select(x => x.Month).ToArray());
+ Assert.AreEqual(new[] { 17, 29, 17 }, dates.Select(x => x.Day).ToArray());
+ Assert.AreEqual(expDates.Select(x => x.DayOfYear).ToArray(), dates.Select(x => x.DayOfYear).ToArray());
+ Assert.AreEqual(expDates.Select(x => x.DayOfWeek).ToArray(), dates.Select(x => x.DayOfWeek).ToArray());
+ Assert.AreEqual(new[] { 15, 23, 15 }, dates.Select(x => x.Hour).ToArray());
+ Assert.AreEqual(new[] { 4, 4, 4 }, dates.Select(x => x.Minute).ToArray());
+ Assert.AreEqual(new[] { 5, 5, 5 }, dates.Select(x => x.Second).ToArray());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Functions.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Functions.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Functions.cs
new file mode 100644
index 0000000..a672d5a
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Functions.cs
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System.Linq;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests where clause.
+ /// </summary>
+ [Test]
+ public void TestWhere()
+ {
+ var cache = GetPersonCache().AsCacheQueryable();
+
+ // Test const and var parameters
+ const int age = 10;
+ var key = 15;
+
+ Assert.AreEqual(age, cache.Where(x => x.Value.Age < age).ToArray().Length);
+ Assert.AreEqual(age, cache.Where(x => x.Value.Address.Zip < age).ToArray().Length);
+ Assert.AreEqual(19, cache.Where(x => x.Value.Age > age && x.Value.Age < 30).ToArray().Length);
+ Assert.AreEqual(20, cache.Where(x => x.Value.Age > age).Count(x => x.Value.Age < 30 || x.Value.Age == 50));
+ Assert.AreEqual(key, cache.Where(x => x.Key < key).ToArray().Length);
+ Assert.AreEqual(key, cache.Where(x => -x.Key > -key).ToArray().Length);
+
+ Assert.AreEqual(1, GetRoleCache().AsCacheQueryable().Where(x => x.Key.Foo < 2).ToArray().Length);
+ Assert.AreEqual(2, GetRoleCache().AsCacheQueryable().Where(x => x.Key.Bar > 2 && x.Value.Name != "11")
+ .ToArray().Length);
+ }
+
+ /// <summary>
+ /// Tests the group by.
+ /// </summary>
+ [Test]
+ public void TestGroupBy()
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+ var orgs = GetOrgCache().AsCacheQueryable();
+
+ // Simple, unordered
+ CollectionAssert.AreEquivalent(new[] { 1000, 1001 },
+ persons.GroupBy(x => x.Value.OrganizationId).Select(x => x.Key).ToArray());
+
+ // Aggregate
+ Assert.AreEqual(1000,
+ persons.GroupBy(x => x.Value.OrganizationId).Select(x => x.Key).OrderBy(x => x).First());
+
+ // Ordering and count
+ var res1 =
+ from p in persons
+ orderby p.Value.Name
+ group p by p.Value.OrganizationId
+ into gs
+ orderby gs.Key
+ where gs.Count() > 10
+ select new { Count = gs.Count(), OrgId = gs.Key, AvgAge = gs.Average(x => x.Value.Age) };
+
+ var resArr = res1.ToArray();
+
+ Assert.AreEqual(new[]
+ {
+ new {Count = PersonCount/2, OrgId = 1000, AvgAge = (double) PersonCount/2 - 1},
+ new {Count = PersonCount/2, OrgId = 1001, AvgAge = (double) PersonCount/2}
+ }, resArr);
+
+ // Join and sum
+ var res2 = persons.Join(orgs.Where(o => o.Key > 10), p => p.Value.OrganizationId, o => o.Key,
+ (p, o) => new { p, o })
+ .GroupBy(x => x.o.Value.Name)
+ .Select(g => new { Org = g.Key, AgeSum = g.Select(x => x.p.Value.Age).Sum() });
+
+ var resArr2 = res2.ToArray();
+
+ Assert.AreEqual(new[]
+ {
+ new {Org = "Org_0", AgeSum = persons.Where(x => x.Value.OrganizationId == 1000).Sum(x => x.Value.Age)},
+ new {Org = "Org_1", AgeSum = persons.Where(x => x.Value.OrganizationId == 1001).Sum(x => x.Value.Age)}
+ }, resArr2);
+ }
+
+ /// <summary>
+ /// Tests the union.
+ /// </summary>
+ [Test]
+ public void TestUnion()
+ {
+ // Direct union
+ var persons = GetPersonCache().AsCacheQueryable();
+ var persons2 = GetSecondPersonCache().AsCacheQueryable();
+
+ var res = persons.Union(persons2).ToArray();
+
+ Assert.AreEqual(PersonCount * 2, res.Length);
+
+ // Subquery
+ var roles = GetRoleCache().AsCacheQueryable().Select(x => -x.Key.Foo);
+ var ids = GetPersonCache().AsCacheQueryable().Select(x => x.Key).Union(roles).ToArray();
+
+ Assert.AreEqual(RoleCount + PersonCount, ids.Length);
+ }
+
+ /// <summary>
+ /// Tests intersect.
+ /// </summary>
+ [Test]
+ public void TestIntersect()
+ {
+ // Direct intersect
+ var persons = GetPersonCache().AsCacheQueryable();
+ var persons2 = GetSecondPersonCache().AsCacheQueryable();
+
+ var res = persons.Intersect(persons2).ToArray();
+
+ Assert.AreEqual(0, res.Length);
+
+ // Subquery
+ var roles = GetRoleCache().AsCacheQueryable().Select(x => x.Key.Foo);
+ var ids = GetPersonCache().AsCacheQueryable().Select(x => x.Key).Intersect(roles).ToArray();
+
+ Assert.AreEqual(RoleCount, ids.Length);
+ }
+
+ /// <summary>
+ /// Tests except.
+ /// </summary>
+ [Test]
+ public void TestExcept()
+ {
+ // Direct except
+ var persons = GetPersonCache().AsCacheQueryable();
+ var persons2 = GetSecondPersonCache().AsCacheQueryable();
+
+ var res = persons.Except(persons2).ToArray();
+
+ Assert.AreEqual(PersonCount, res.Length);
+
+ // Subquery
+ var roles = GetRoleCache().AsCacheQueryable().Select(x => x.Key.Foo);
+ var ids = GetPersonCache().AsCacheQueryable().Select(x => x.Key).Except(roles).ToArray();
+
+ Assert.AreEqual(PersonCount - RoleCount, ids.Length);
+ }
+
+ /// <summary>
+ /// Tests ordering.
+ /// </summary>
+ [Test]
+ public void TestOrdering()
+ {
+ var persons = GetPersonCache().AsCacheQueryable()
+ .OrderByDescending(x => x.Key)
+ .ThenBy(x => x.Value.Age)
+ .ToArray();
+
+ Assert.AreEqual(Enumerable.Range(0, PersonCount).Reverse().ToArray(),
+ persons.Select(x => x.Key).ToArray());
+
+ var personsByOrg = GetPersonCache().AsCacheQueryable()
+ .Join(GetOrgCache().AsCacheQueryable(), p => p.Value.OrganizationId, o => o.Value.Id,
+ (p, o) => new
+ {
+ PersonId = p.Key,
+ PersonName = p.Value.Name.ToUpper(),
+ OrgName = o.Value.Name
+ })
+ .OrderBy(x => x.OrgName.ToLower())
+ .ThenBy(x => x.PersonName)
+ .ToArray();
+
+ var expectedIds = Enumerable.Range(0, PersonCount)
+ .OrderBy(x => (x % 2).ToString())
+ .ThenBy(x => x.ToString())
+ .ToArray();
+
+ var actualIds = personsByOrg.Select(x => x.PersonId).ToArray();
+
+ Assert.AreEqual(expectedIds, actualIds);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
new file mode 100644
index 0000000..9430dd8
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Introspection.cs
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Linq;
+ using Apache.Ignite.Core.Cache.Query;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests the introspection.
+ /// </summary>
+ [Test]
+ public void TestIntrospection()
+ {
+ var cache = GetPersonCache();
+
+ // Check regular query
+ var query = cache.AsCacheQueryable(new QueryOptions
+ {
+ Local = true,
+ PageSize = 999,
+ EnforceJoinOrder = true,
+ Timeout = TimeSpan.FromSeconds(2.5),
+ ReplicatedOnly = true,
+ Colocated = true
+ }).Where(x => x.Key > 10).ToCacheQueryable();
+
+ Assert.AreEqual(cache.Name, query.CacheName);
+ Assert.AreEqual(cache.Ignite, query.Ignite);
+
+ var fq = query.GetFieldsQuery();
+
+ Assert.AreEqual(
+ GetSqlEscapeAll()
+ ? "select _T0._KEY, _T0._VAL from \"person_org\".\"Person\" as _T0 where (_T0.\"_KEY\" > ?)"
+ : "select _T0._KEY, _T0._VAL from \"person_org\".Person as _T0 where (_T0._KEY > ?)",
+ fq.Sql);
+
+ Assert.AreEqual(new[] { 10 }, fq.Arguments);
+ Assert.IsTrue(fq.Local);
+ Assert.AreEqual(PersonCount - 11, cache.QueryFields(fq).GetAll().Count);
+ Assert.AreEqual(999, fq.PageSize);
+ Assert.IsFalse(fq.EnableDistributedJoins);
+ Assert.IsTrue(fq.EnforceJoinOrder);
+ Assert.IsTrue(fq.ReplicatedOnly);
+ Assert.IsTrue(fq.Colocated);
+ Assert.AreEqual(TimeSpan.FromSeconds(2.5), fq.Timeout);
+
+ var str = query.ToString();
+ Assert.AreEqual(GetSqlEscapeAll()
+ ? "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+ "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".\"Person\" as _T0 where " +
+ "(_T0.\"_KEY\" > ?), Arguments=[10], " +
+ "Local=True, PageSize=999, EnableDistributedJoins=False, EnforceJoinOrder=True, " +
+ "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True, Schema=]]"
+ : "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+ "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".Person as _T0 where " +
+ "(_T0._KEY > ?), Arguments=[10], " +
+ "Local=True, PageSize=999, EnableDistributedJoins=False, EnforceJoinOrder=True, " +
+ "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True, Schema=]]", str);
+
+ // Check fields query
+ var fieldsQuery = (ICacheQueryable)cache.AsCacheQueryable().Select(x => x.Value.Name);
+
+ Assert.AreEqual(cache.Name, fieldsQuery.CacheName);
+ Assert.AreEqual(cache.Ignite, fieldsQuery.Ignite);
+
+ fq = fieldsQuery.GetFieldsQuery();
+ Assert.AreEqual(GetSqlEscapeAll()
+ ? "select _T0.\"Name\" from \"person_org\".\"Person\" as _T0"
+ : "select _T0.NAME from \"person_org\".Person as _T0",
+ fq.Sql);
+
+ Assert.IsFalse(fq.Local);
+ Assert.AreEqual(SqlFieldsQuery.DefaultPageSize, fq.PageSize);
+ Assert.IsFalse(fq.EnableDistributedJoins);
+ Assert.IsFalse(fq.EnforceJoinOrder);
+
+ str = fieldsQuery.ToString();
+ Assert.AreEqual(GetSqlEscapeAll()
+ ? "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+ "[Sql=select _T0.\"Name\" from \"person_org\".\"Person\" as _T0, Arguments=[], Local=False, " +
+ "PageSize=1024, EnableDistributedJoins=False, EnforceJoinOrder=False, " +
+ "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False, Schema=]]"
+ : "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+ "[Sql=select _T0.NAME from \"person_org\".Person as _T0, Arguments=[], Local=False, " +
+ "PageSize=1024, EnableDistributedJoins=False, EnforceJoinOrder=False, " +
+ "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False, Schema=]]", str);
+
+ // Check distributed joins flag propagation
+ var distrQuery = cache.AsCacheQueryable(new QueryOptions { EnableDistributedJoins = true })
+ .Where(x => x.Key > 10 && x.Value.Age > 20 && x.Value.Name.Contains("x"));
+
+ query = distrQuery.ToCacheQueryable();
+
+ Assert.IsTrue(query.GetFieldsQuery().EnableDistributedJoins);
+
+ str = distrQuery.ToString();
+ Assert.AreEqual(GetSqlEscapeAll()
+ ? "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+ "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".\"Person\" as _T0 where " +
+ "(((_T0.\"_KEY\" > ?) and (_T0.\"age1\" > ?)) " +
+ "and (_T0.\"Name\" like \'%\' || ? || \'%\') ), Arguments=[10, 20, x], Local=False, " +
+ "PageSize=1024, EnableDistributedJoins=True, EnforceJoinOrder=False, " +
+ "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False, Schema=]]"
+ : "CacheQueryable [CacheName=person_org, TableName=Person, Query=SqlFieldsQuery " +
+ "[Sql=select _T0._KEY, _T0._VAL from \"person_org\".Person as _T0 where " +
+ "(((_T0._KEY > ?) and (_T0.AGE1 > ?)) " +
+ "and (_T0.NAME like \'%\' || ? || \'%\') ), Arguments=[10, 20, x], Local=False, " +
+ "PageSize=1024, EnableDistributedJoins=True, EnforceJoinOrder=False, " +
+ "Timeout=00:00:00, ReplicatedOnly=False, Colocated=False, Schema=]]", str);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.LocalCollection.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.LocalCollection.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.LocalCollection.cs
new file mode 100644
index 0000000..e7e05f4
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.LocalCollection.cs
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests the join with local collection.
+ /// </summary>
+ [Test]
+ public void TestLocalJoin()
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+ var orgs = GetOrgCache().AsCacheQueryable();
+
+ var localOrgs = orgs
+ .Select(e => e.Value)
+ .ToArray();
+
+ var allOrganizationIds = localOrgs
+ .Select(e => e.Id)
+ .ToArray();
+
+ // Join with local collection
+ var qry1 = persons.Join(allOrganizationIds,
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ )
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, qry1.Length);
+
+ // Join using expression in innerKeySelector
+ var qry2 = persons.Join(allOrganizationIds,
+ pe => pe.Value.OrganizationId,
+ i => i + 1 - 1,
+ (pe, o) => pe
+ )
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, qry2.Length);
+
+ // Local collection subquery
+ var qry3 = persons.Join(localOrgs.Select(e => e.Id),
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ )
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, qry3.Length);
+
+ // Compiled query
+ var qry4 = CompiledQuery.Compile(() => persons.Join(allOrganizationIds,
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ ));
+
+ Assert.AreEqual(PersonCount, qry4().Count());
+
+ // Compiled query with outer join
+ var qry4A = CompiledQuery.Compile(() => persons.Join(new int[] { }.DefaultIfEmpty(),
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ ));
+
+ Assert.AreEqual(PersonCount, qry4A().Count());
+
+ // Compiled query
+ var qry5 = CompiledQuery.Compile(() => persons.Join(new[] { -1, -2 }.DefaultIfEmpty(),
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ ));
+
+ Assert.AreEqual(PersonCount, qry5().Count());
+
+ // Outer join
+ var qry6 = persons.Join(new[] { -1, -2 }.DefaultIfEmpty(),
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ )
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, qry6.Length);
+
+ // Join with local list
+ var qry7 = persons.Join(new List<int> { 1000, 1001, 1002, 1003 },
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ )
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, qry7.Length);
+
+ // Join with local list variable
+ var list = new List<int> { 1000, 1001, 1002, 1003 };
+ var qry8 = persons.Join(list,
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ )
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, qry8.Length);
+ }
+
+ /// <summary>
+ /// Tests the compiled query containing join with local collection passed as parameter.
+ /// </summary>
+ [Test]
+ [Ignore("IGNITE-5404")]
+ public void TestLocalJoinCompiledQueryParameter()
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+ var orgs = GetOrgCache().AsCacheQueryable();
+
+ var localOrgs = orgs
+ .Select(e => e.Value)
+ .ToArray();
+
+ var allOrganizationIds = localOrgs
+ .Select(e => e.Id)
+ .ToArray();
+
+ // Join with local collection passed as parameter
+ var qry1 = CompiledQuery.Compile((IEnumerable<int> lc) => persons.Join(lc,
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ ));
+
+ Assert.AreEqual(PersonCount, qry1(allOrganizationIds).Count());
+
+ //Compiled query with outer join
+ var qry2 = CompiledQuery.Compile((IEnumerable<int> lc) => persons.Join(lc.DefaultIfEmpty(),
+ pe => pe.Value.OrganizationId,
+ i => i,
+ (pe, o) => pe
+ ));
+
+ Assert.AreEqual(PersonCount, qry2(new[] { -11 }).Count());
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/84c7427a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.cs
new file mode 100644
index 0000000..f589329
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/Query/Linq/CacheLinqTest.Join.cs
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ReSharper disable SuspiciousTypeConversion.Global
+// ReSharper disable MemberCanBePrivate.Global
+// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
+// ReSharper disable UnusedAutoPropertyAccessor.Global
+// ReSharper disable StringIndexOfIsCultureSpecific.1
+// ReSharper disable StringIndexOfIsCultureSpecific.2
+// ReSharper disable StringCompareToIsCultureSpecific
+// ReSharper disable StringCompareIsCultureSpecific.1
+// ReSharper disable UnusedMemberInSuper.Global
+namespace Apache.Ignite.Core.Tests.Cache.Query.Linq
+{
+ using System;
+ using System.Linq;
+ using Apache.Ignite.Linq;
+ using NUnit.Framework;
+
+ /// <summary>
+ /// Tests LINQ.
+ /// </summary>
+ public partial class CacheLinqTest
+ {
+ /// <summary>
+ /// Tests the same cache join.
+ /// </summary>
+ [Test]
+ public void TestSameCacheJoin()
+ {
+ // Select persons in specific organization
+ var organizations = GetOrgCache().AsCacheQueryable();
+ var persons = GetPersonCache().AsCacheQueryable();
+
+ var res = persons.Join(organizations, person => person.Value.OrganizationId + 3, org => org.Value.Id + 3,
+ (person, org) => new { Person = person.Value, Org = org.Value })
+ .Where(x => x.Org.Name == "Org_1")
+ .ToList();
+
+ Assert.AreEqual(PersonCount / 2, res.Count);
+
+ Assert.IsTrue(res.All(r => r.Person.OrganizationId == r.Org.Id));
+
+ // Test full projection (selects pair of ICacheEntry)
+ var res2 = persons.Join(organizations, person => person.Value.OrganizationId - 1, org => org.Value.Id - 1,
+ (person, org) => new { Person = person, Org = org })
+ .Where(x => x.Org.Value.Name.ToLower() == "org_0")
+ .ToList();
+
+ Assert.AreEqual(PersonCount / 2, res2.Count);
+ }
+
+ /// <summary>
+ /// Tests the multi key join.
+ /// </summary>
+ [Test]
+ public void TestMultiKeyJoin()
+ {
+ var organizations = GetOrgCache().AsCacheQueryable();
+ var persons = GetPersonCache().AsCacheQueryable();
+
+ var multiKey =
+ from person in persons
+ join org in organizations on
+ new { OrgId = person.Value.OrganizationId, person.Key } equals
+ new { OrgId = org.Value.Id, Key = org.Key - 1000 }
+ where person.Key == 1
+ select new { PersonName = person.Value.Name, OrgName = org.Value.Name };
+
+ Assert.AreEqual(" Person_1 ", multiKey.Single().PersonName);
+ }
+
+ /// <summary>
+ /// Tests the cross cache join.
+ /// </summary>
+ [Test]
+ public void TestCrossCacheJoin()
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+ var roles = GetRoleCache().AsCacheQueryable();
+
+ var res = persons.Join(roles, person => person.Key, role => role.Key.Foo, (person, role) => role)
+ .OrderBy(x => x.Key.Bar)
+ .ToArray();
+
+ Assert.AreEqual(RoleCount, res.Length);
+ Assert.AreEqual(101, res[0].Key.Bar);
+ }
+
+ /// <summary>
+ /// Tests the cross cache join.
+ /// </summary>
+ [Test]
+ public void TestCrossCacheJoinInline()
+ {
+ var res = GetPersonCache().AsCacheQueryable().Join(GetRoleCache().AsCacheQueryable(),
+ person => person.Key, role => role.Key.Foo, (person, role) => role)
+ .OrderBy(x => x.Key.Bar).ToArray();
+
+ Assert.AreEqual(RoleCount, res.Length);
+ Assert.AreEqual(101, res[0].Key.Bar);
+ }
+
+ /// <summary>
+ /// Tests the multi cache join.
+ /// </summary>
+ [Test]
+ public void TestMultiCacheJoin()
+ {
+ var organizations = GetOrgCache().AsCacheQueryable();
+ var persons = GetPersonCache().AsCacheQueryable();
+ var roles = GetRoleCache().AsCacheQueryable();
+
+ var res = roles.Join(persons, role => role.Key.Foo, person => person.Key,
+ (role, person) => new { person, role })
+ .Join(organizations, pr => pr.person.Value.OrganizationId, org => org.Value.Id,
+ (pr, org) => new { org, pr.person, pr.role }).ToArray();
+
+ Assert.AreEqual(RoleCount, res.Length);
+ }
+
+ /// <summary>
+ /// Tests the multi cache join subquery.
+ /// </summary>
+ [Test]
+ public void TestMultiCacheJoinSubquery()
+ {
+ var organizations = GetOrgCache().AsCacheQueryable().Where(x => x.Key == 1001);
+ var persons = GetPersonCache().AsCacheQueryable().Where(x => x.Key < 20);
+ var roles = GetRoleCache().AsCacheQueryable().Where(x => x.Key.Foo >= 0);
+
+ var res = roles.Join(persons, role => role.Key.Foo, person => person.Key,
+ (role, person) => new { person, role })
+ .Join(organizations, pr => pr.person.Value.OrganizationId, org => org.Value.Id,
+ (pr, org) => new { org, pr.person, pr.role }).ToArray();
+
+ Assert.AreEqual(2, res.Length);
+ }
+
+ /// <summary>
+ /// Tests the outer join.
+ /// </summary>
+ [Test]
+ public void TestOuterJoin()
+ {
+ var persons = GetPersonCache().AsCacheQueryable();
+ var roles = GetRoleCache().AsCacheQueryable();
+
+ var res = persons.Join(roles.Where(r => r.Key.Bar > 0).DefaultIfEmpty(),
+ person => person.Key, role => role.Key.Foo,
+ (person, role) => new
+ {
+ PersonName = person.Value.Name,
+ RoleName = role.Value.Name
+ })
+ .Where(x => x.PersonName != " ")
+ .ToArray();
+
+ Assert.AreEqual(PersonCount, res.Length);
+ }
+
+ /// <summary>
+ /// Tests the subquery join.
+ /// </summary>
+ [Test]
+ public void TestSubqueryJoin()
+ {
+ var persons = GetPersonCache().AsCacheQueryable().Where(x => x.Key >= 0);
+
+ var orgs = GetOrgCache().AsCacheQueryable().Where(x => x.Key > 10);
+
+ var qry1 = persons.Join(orgs,
+ p => p.Value.OrganizationId,
+ o => o.Value.Id,
+ (p, o) => p)
+ .Where(x => x.Key >= 0)
+ .ToList();
+
+ Assert.AreEqual(PersonCount, qry1.Count);
+
+ // With selector inline
+ var qry2 = persons
+ .Join(orgs.Select(orgEntry => orgEntry.Key),
+ e => e.Value.OrganizationId,
+ i => i,
+ (e, i) => e)
+ .ToList();
+
+ Assert.AreEqual(PersonCount, qry2.Count);
+
+ // With selector from variable
+ var innerSequence = orgs
+ .Select(orgEntry => orgEntry.Key);
+
+ var qry3 = persons
+ .Join(innerSequence,
+ e => e.Value.OrganizationId,
+ i => i,
+ (e, i) => e)
+ .ToList();
+
+ Assert.AreEqual(PersonCount, qry3.Count);
+ }
+
+ /// <summary>
+ /// Tests the invalid join.
+ /// </summary>
+ [Test]
+ public void TestInvalidJoin()
+ {
+ var localComplexTypeCollection = GetOrgCache().AsCacheQueryable()
+ .Select(e => e.Value)
+ .ToArray();
+
+ // Join on non-IQueryable with complex(not supported) type
+ var ex = Assert.Throws<NotSupportedException>(() =>
+ // ReSharper disable once ReturnValueOfPureMethodIsNotUsed
+ {
+ GetPersonCache().AsCacheQueryable().Join(localComplexTypeCollection, p => p.Value.OrganizationId,
+ o => o.Id, (p, o) => p).ToList();
+ });
+
+ Assert.IsTrue(ex.Message.StartsWith("Not supported item type for Join with local collection"));
+ }
+
+ /// <summary>
+ /// Tests query with multiple from clause.
+ /// </summary>
+ [Test]
+ public void TestMultipleFrom()
+ {
+ var persons = GetPersonCache().AsCacheQueryable().Where(x => x.Key < PersonCount);
+ var roles = GetRoleCache().AsCacheQueryable().Where(x => x.Value.Name != "1");
+
+ var all = persons.SelectMany(person => roles.Select(role => new { role, person }));
+ Assert.AreEqual(RoleCount * PersonCount, all.Count());
+
+ var filtered =
+ from person in persons
+ from role in roles
+ where person.Key == role.Key.Foo
+ select new { Person = person.Value.Name, Role = role.Value.Name };
+
+ var res = filtered.ToArray();
+
+ Assert.AreEqual(RoleCount, res.Length);
+ }
+
+ /// <summary>
+ /// Tests query with multiple from clause with inline query sources.
+ /// </summary>
+ [Test]
+ public void TestMultipleFromInline()
+ {
+ var filtered =
+ from person in GetPersonCache().AsCacheQueryable()
+ from role in GetRoleCache().AsCacheQueryable()
+ where person.Key == role.Key.Foo
+ select new { Person = person.Value.Name, Role = role.Value.Name };
+
+ var res = filtered.ToArray();
+
+ Assert.AreEqual(RoleCount, res.Length);
+ }
+
+ /// <summary>
+ /// Tests the join of a table to itself.
+ /// </summary>
+ [Test]
+ public void TestSelfJoin()
+ {
+ // Different queryables
+ var p1 = GetPersonCache().AsCacheQueryable();
+ var p2 = GetPersonCache().AsCacheQueryable();
+
+ var qry = p1.Join(p2, x => x.Value.Age, x => x.Key, (x, y) => x.Key);
+ Assert.AreEqual(PersonCount, qry.ToArray().Distinct().Count());
+
+ // Same queryables
+ var qry2 = p1.Join(p1, x => x.Value.Age, x => x.Key, (x, y) => x.Key);
+ Assert.AreEqual(PersonCount, qry2.ToArray().Distinct().Count());
+ }
+
+ /// <summary>
+ /// Tests the join of a table to itself with inline queryable.
+ /// </summary>
+ [Test]
+ public void TestSelfJoinInline()
+ {
+ var qry = GetPersonCache().AsCacheQueryable().Join(GetPersonCache().AsCacheQueryable(),
+ x => x.Value.Age, x => x.Key, (x, y) => x.Key);
+
+ Assert.AreEqual(PersonCount, qry.ToArray().Distinct().Count());
+ }
+ }
+}
\ No newline at end of file