Repository: ignite Updated Branches: refs/heads/master f08c9d3ad -> 1f4337527
IGNITE-6338 .NET: Thin client: LINQ This closes #3125 Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/1f433752 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/1f433752 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/1f433752 Branch: refs/heads/master Commit: 1f4337527ee2f75b90b46a297b5056064e78eb40 Parents: f08c9d3 Author: Pavel Tupitsyn <[email protected]> Authored: Mon Dec 4 11:14:32 2017 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Mon Dec 4 11:14:32 2017 +0300 ---------------------------------------------------------------------- .../Apache.Ignite.Core.Tests.DotNetCore.csproj | 2 + .../Apache.Ignite.Core.Tests.csproj | 2 + .../Query/Linq/CacheLinqTest.Introspection.cs | 8 +- .../Client/Cache/CreateCacheTest.cs | 1 - .../Client/Cache/LinqTest.cs | 117 +++++++++++ .../Client/Cache/SqlQueryTest.cs | 43 +--- .../Client/Cache/SqlQueryTestBase.cs | 68 +++++++ .../Client/RawSocketTest.cs | 1 - .../TestUtils.Windows.cs | 2 - .../Impl/Cache/ICacheInternal.cs | 6 + .../Impl/Client/Cache/CacheClient.cs | 64 +++++- .../Client/Cache/Query/ClientQueryCursorBase.cs | 4 +- .../Apache.Ignite.Linq.csproj | 3 +- .../CacheClientLinqExtensions.cs | 131 ++++++++++++ .../Apache.Ignite.Linq/CacheExtensions.cs | 195 ------------------ .../Apache.Ignite.Linq/CacheLinqExtensions.cs | 197 +++++++++++++++++++ .../Apache.Ignite.Linq/ICacheQueryable.cs | 1 + .../Impl/CacheFieldsQueryProvider.cs | 2 +- .../Apache.Ignite.Linq/Impl/CacheQueryable.cs | 8 +- .../Impl/CacheQueryableBase.cs | 1 + .../dotnet/Apache.Ignite/IgniteRunner.cs | 1 - 21 files changed, 598 insertions(+), 259 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj index 5d735eb..8e4de7f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests.DotNetCore/Apache.Ignite.Core.Tests.DotNetCore.csproj @@ -64,7 +64,9 @@ <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\EmptyObject.cs" Link="ThinClient\Cache\EmptyObject.cs" /> <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\Person.cs" Link="ThinClient\Cache\Person.cs" /> <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\ScanQueryTest.cs" Link="ThinClient\Cache\ScanQueryTest.cs" /> + <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\SqlQueryTestBase.cs" Link="ThinClient\Cache\SqlQueryTestBase.cs" /> <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\SqlQueryTest.cs" Link="ThinClient\Cache\SqlQueryTest.cs" /> + <Compile Include="..\Apache.Ignite.Core.Tests\Client\Cache\LinqTest.cs" Link="ThinClient\Cache\LinqTest.cs" /> <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientConnectionTest.cs" Link="ThinClient\ClientConnectionTest.cs" /> <Compile Include="..\Apache.Ignite.Core.Tests\Client\ClientTestBase.cs" Link="ThinClient\ClientTestBase.cs" /> <Compile Include="..\Apache.Ignite.Core.Tests\Client\IgniteClientConfigurationTest.cs" Link="ThinClient\IgniteClientConfigurationTest.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj index 8bd8f28..77b2e6e 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj @@ -113,9 +113,11 @@ <Compile Include="Client\Cache\ClientCacheConfigurationTest.cs" /> <Compile Include="Client\Cache\EmptyObject.cs" /> <Compile Include="Client\Cache\CreateCacheTest.cs" /> + <Compile Include="Client\Cache\LinqTest.cs" /> <Compile Include="Client\Cache\ScanQueryTest.cs" /> <Compile Include="Client\Cache\Person.cs" /> <Compile Include="Client\Cache\SqlQueryTest.cs" /> + <Compile Include="Client\Cache\SqlQueryTestBase.cs" /> <Compile Include="Client\ClientTestBase.cs" /> <Compile Include="Client\RawSocketTest.cs" /> <Compile Include="Client\ClientConnectionTest.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/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 index a13131b..6e7483e 100644 --- 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 @@ -58,7 +58,9 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Linq }).Where(x => x.Key > 10).ToCacheQueryable(); Assert.AreEqual(cache.Name, query.CacheName); +#pragma warning disable 618 // Type or member is obsolete Assert.AreEqual(cache.Ignite, query.Ignite); +#pragma warning restore 618 // Type or member is obsolete var fq = query.GetFieldsQuery(); @@ -93,10 +95,12 @@ namespace Apache.Ignite.Core.Tests.Cache.Query.Linq "Timeout=00:00:02.5000000, ReplicatedOnly=True, Colocated=True, Schema=, Lazy=True]]", str); // Check fields query - var fieldsQuery = (ICacheQueryable)cache.AsCacheQueryable().Select(x => x.Value.Name); + var fieldsQuery = cache.AsCacheQueryable().Select(x => x.Value.Name).ToCacheQueryable(); Assert.AreEqual(cache.Name, fieldsQuery.CacheName); - Assert.AreEqual(cache.Ignite, fieldsQuery.Ignite); +#pragma warning disable 618 // Type or member is obsolete + Assert.AreEqual(cache.Ignite, query.Ignite); +#pragma warning restore 618 // Type or member is obsolete fq = fieldsQuery.GetFieldsQuery(); Assert.AreEqual(GetSqlEscapeAll() http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs index 4489462..94ae6cd 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/CreateCacheTest.cs @@ -22,7 +22,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache using Apache.Ignite.Core.Client; using Apache.Ignite.Core.Client.Cache; using Apache.Ignite.Core.Configuration; - using Apache.Ignite.Core.Impl.Client; using Apache.Ignite.Core.Tests.Cache; using NUnit.Framework; http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs new file mode 100644 index 0000000..e61f712 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/LinqTest.cs @@ -0,0 +1,117 @@ +/* + * 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.Client.Cache +{ + using System; + using System.Linq; + using Apache.Ignite.Linq; + using NUnit.Framework; + + /// <summary> + /// Tests LINQ in thin client. + /// </summary> + public class LinqTest : SqlQueryTestBase + { + /// <summary> + /// Tests basic queries. + /// </summary> + [Test] + public void TestBasicQueries() + { + var cache = GetClientCache<Person>(); + + // All items. + var qry = cache.AsCacheQueryable(); + Assert.AreEqual(Count, qry.Count()); + + // Filter. + qry = cache.AsCacheQueryable().Where(x => x.Value.Name.EndsWith("7")); + Assert.AreEqual(7, qry.Single().Key); + Assert.AreEqual("select _T0._KEY, _T0._VAL from \"cache\".PERSON as _T0 where (_T0.NAME like '%' || ?) ", + qry.ToCacheQueryable().GetFieldsQuery().Sql); + + // DateTime. + var arg = DateTime.UtcNow.AddDays(Count - 1); + var qry2 = cache.AsCacheQueryable(false, "Person") + .Where(x => x.Value.DateTime > arg).Select(x => x.Key); + Assert.AreEqual(Count, qry2.Single()); + } + + /// <summary> + /// Tests joins. + /// </summary> + [Test] + public void TestJoins() + { + var cache1 = Client.GetCache<int, Person>(CacheName); + var cache2 = Client.GetCache<int, Person>(CacheName2); + + // Non-distributed join returns incomplete results. + var persons1 = cache1.AsCacheQueryable(false); + var persons2 = cache2.AsCacheQueryable(); + + var qry = persons1 + .Join(persons2, p1 => p1.Value.Id, p2 => Count + 1 - p2.Value.Id, (p1, p2) => p2.Value.Name); + + Assert.Greater(Count, qry.ToArray().Length); + + + // Distributed join fixes the problem. + persons1 = cache1.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true}); + persons2 = cache2.AsCacheQueryable(new QueryOptions {EnableDistributedJoins = true}); + + var qry2 = + from p1 in persons1 + join p2 in persons2 on p1.Value.Id equals Count + 1 - p2.Value.Id + select p2.Value.DateTime; + + Assert.AreEqual(Count, qry2.ToArray().Length); + } + + /// <summary> + /// Tests DML via LINQ. + /// </summary> + [Test] + public void TestDml() + { + var cache = GetClientCache<Person>(); + + Assert.AreEqual(Count, cache.GetSize()); + + var res = cache.AsCacheQueryable().Where(x => x.Key % 3 == 0).RemoveAll(); + Assert.AreEqual(Count / 3, res); + + Assert.AreEqual(Count - res, cache.GetSize()); + } + + /// <summary> + /// Tests the compiled query. + /// </summary> + [Test] + public void TestCompiledQuery() + { + var cache = GetClientCache<Person>(); + var persons = cache.AsCacheQueryable(); + + var qry = CompiledQuery.Compile((int id) => persons.Where(x => x.Value.Id == id)); + + Assert.AreEqual(1, qry(1).Single().Key); + Assert.AreEqual(3, qry(3).Single().Key); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs index 720a71b..6f6df11 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTest.cs @@ -19,7 +19,6 @@ namespace Apache.Ignite.Core.Tests.Client.Cache { using System; using System.Linq; - using Apache.Ignite.Core.Cache.Configuration; using Apache.Ignite.Core.Cache.Query; using Apache.Ignite.Core.Client; using NUnit.Framework; @@ -27,36 +26,9 @@ namespace Apache.Ignite.Core.Tests.Client.Cache /// <summary> /// Tests SQL queries via thin client. /// </summary> - public class SqlQueryTest : ClientTestBase + public class SqlQueryTest : SqlQueryTestBase { /// <summary> - /// Cache item count. - /// </summary> - private const int Count = 10; - - /// <summary> - /// Second cache name. - /// </summary> - private const string CacheName2 = CacheName + "2"; - - /// <summary> - /// Initializes a new instance of the <see cref="ScanQueryTest"/> class. - /// </summary> - public SqlQueryTest() : base(2) - { - // No-op. - } - - /// <summary> - /// Sets up the test. - /// </summary> - public override void TestSetUp() - { - InitCache(CacheName); - InitCache(CacheName2); - } - - /// <summary> /// Tests the SQL query. /// </summary> [Test] @@ -251,18 +223,5 @@ namespace Apache.Ignite.Core.Tests.Client.Cache Assert.AreEqual(1, res[0][0]); Assert.AreEqual("baz", cache[-10].Name); } - - /// <summary> - /// Initializes the cache. - /// </summary> - private static void InitCache(string cacheName) - { - var cache = Ignition.GetIgnite().GetOrCreateCache<int, Person>( - new CacheConfiguration(cacheName, new QueryEntity(typeof(int), typeof(Person)))); - - cache.RemoveAll(); - - cache.PutAll(Enumerable.Range(1, Count).ToDictionary(x => x, x => new Person(x))); - } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs new file mode 100644 index 0000000..7efcb9c --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/Cache/SqlQueryTestBase.cs @@ -0,0 +1,68 @@ +/* + * 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.Client.Cache +{ + using System.Linq; + using Apache.Ignite.Core.Cache.Configuration; + + /// <summary> + /// Base class for SQL tests. + /// </summary> + public class SqlQueryTestBase : ClientTestBase + { + /// <summary> + /// Cache item count. + /// </summary> + protected const int Count = 10; + + /// <summary> + /// Second cache name. + /// </summary> + protected const string CacheName2 = CacheName + "2"; + + /// <summary> + /// Initializes a new instance of the <see cref="ScanQueryTest"/> class. + /// </summary> + public SqlQueryTestBase() : base(2) + { + // No-op. + } + + /// <summary> + /// Sets up the test. + /// </summary> + public override void TestSetUp() + { + InitCache(CacheName); + InitCache(CacheName2); + } + + /// <summary> + /// Initializes the cache. + /// </summary> + private static void InitCache(string cacheName) + { + var cache = Ignition.GetIgnite().GetOrCreateCache<int, Person>( + new CacheConfiguration(cacheName, new QueryEntity(typeof(int), typeof(Person)))); + + cache.RemoveAll(); + + cache.PutAll(Enumerable.Range(1, Count).ToDictionary(x => x, x => new Person(x))); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs index b088bb6..8ab110f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/RawSocketTest.cs @@ -25,7 +25,6 @@ namespace Apache.Ignite.Core.Tests.Client using Apache.Ignite.Core.Impl; using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Binary.IO; - using Apache.Ignite.Core.Impl.Client; using NUnit.Framework; /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs index 14b58f2..2169630 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.Windows.cs @@ -20,10 +20,8 @@ namespace Apache.Ignite.Core.Tests using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; - using System.Linq; using Apache.Ignite.Core.Configuration; using Apache.Ignite.Core.Impl; - using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Common; using Apache.Ignite.Core.Tests.Process; using NUnit.Framework; http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs index 0349db8..1ec5341 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs @@ -19,6 +19,7 @@ namespace Apache.Ignite.Core.Impl.Cache { using System; using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Cache.Configuration; using Apache.Ignite.Core.Cache.Query; /// <summary> @@ -50,5 +51,10 @@ namespace Apache.Ignite.Core.Impl.Cache /// </returns> T DoOutInOpExtension<T>(int extensionId, int opCode, Action<IBinaryRawWriter> writeAction, Func<IBinaryRawReader, T> readFunc); + + /// <summary> + /// Gets the cache configuration. + /// </summary> + CacheConfiguration GetConfiguration(); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs index 45c0b0f..93829c2 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/CacheClient.cs @@ -20,9 +20,11 @@ namespace Apache.Ignite.Core.Impl.Client.Cache using System; using System.Collections.Generic; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.IO; using Apache.Ignite.Core.Binary; using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Configuration; using Apache.Ignite.Core.Cache.Query; using Apache.Ignite.Core.Client; using Apache.Ignite.Core.Client.Cache; @@ -37,7 +39,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache /// <summary> /// Client cache implementation. /// </summary> - internal sealed class CacheClient<TK, TV> : ICacheClient<TK, TV> + internal sealed class CacheClient<TK, TV> : ICacheClient<TK, TV>, ICacheInternal { /** Scan query filter platform code: .NET filter. */ private const byte FilterPlatformDotnet = 2; @@ -188,10 +190,17 @@ namespace Apache.Ignite.Core.Impl.Client.Cache IgniteArgumentCheck.NotNull(sqlFieldsQuery, "sqlFieldsQuery"); IgniteArgumentCheck.NotNull(sqlFieldsQuery.Sql, "sqlFieldsQuery.Sql"); - return DoOutInOp(ClientOp.QuerySqlFields, w => WriteSqlFieldsQuery(w, sqlFieldsQuery), - s => new ClientFieldsQueryCursor( - _ignite, s.ReadLong(), _keepBinary, s, ClientOp.QuerySqlFieldsCursorGetPage, - ClientFieldsQueryCursor.ReadColumns(_marsh.StartUnmarshal(s)))); + return DoOutInOp(ClientOp.QuerySqlFields, + w => WriteSqlFieldsQuery(w, sqlFieldsQuery), + s => GetFieldsCursor(s)); + } + + /** <inheritDoc /> */ + public IQueryCursor<T> QueryFields<T>(SqlFieldsQuery sqlFieldsQuery, Func<IBinaryRawReader, int, T> readerFunc) + { + return DoOutInOp(ClientOp.QuerySqlFields, + w => WriteSqlFieldsQuery(w, sqlFieldsQuery, false), + s => GetFieldsCursorNoColumnNames(s, readerFunc)); } /** <inheritDoc /> */ @@ -361,6 +370,12 @@ namespace Apache.Ignite.Core.Impl.Client.Cache } /** <inheritDoc /> */ + CacheConfiguration ICacheInternal.GetConfiguration() + { + return GetConfiguration().ToCacheConfiguration(); + } + + /** <inheritDoc /> */ public ICacheClient<TK1, TV1> WithKeepBinary<TK1, TV1>() { if (_keepBinary) @@ -380,6 +395,15 @@ namespace Apache.Ignite.Core.Impl.Client.Cache return new CacheClient<TK1, TV1>(_ignite, _name, true); } + /** <inheritDoc /> */ + [ExcludeFromCodeCoverage] + public T DoOutInOpExtension<T>(int extensionId, int opCode, Action<IBinaryRawWriter> writeAction, + Func<IBinaryRawReader, T> readFunc) + { + // Should not be called, there are no usages for thin client. + throw IgniteClient.GetClientNotSupportedException(); + } + /// <summary> /// Does the out in op. /// </summary> @@ -492,7 +516,8 @@ namespace Apache.Ignite.Core.Impl.Client.Cache /// <summary> /// Writes the SQL fields query. /// </summary> - private static void WriteSqlFieldsQuery(IBinaryRawWriter writer, SqlFieldsQuery qry) + private static void WriteSqlFieldsQuery(IBinaryRawWriter writer, SqlFieldsQuery qry, + bool includeColumns = true) { Debug.Assert(qry != null); @@ -513,10 +538,33 @@ namespace Apache.Ignite.Core.Impl.Client.Cache writer.WriteBoolean(qry.Colocated); writer.WriteBoolean(qry.Lazy); writer.WriteTimeSpanAsLong(qry.Timeout); + writer.WriteBoolean(includeColumns); - // Always include field names. - writer.WriteBoolean(true); + } + + /// <summary> + /// Gets the fields cursor. + /// </summary> + private ClientFieldsQueryCursor GetFieldsCursor(IBinaryStream s) + { + var cursorId = s.ReadLong(); + var columnNames = ClientFieldsQueryCursor.ReadColumns(_marsh.StartUnmarshal(s)); + + return new ClientFieldsQueryCursor(_ignite, cursorId, _keepBinary, s, + ClientOp.QuerySqlFieldsCursorGetPage, columnNames); + } + + /// <summary> + /// Gets the fields cursor. + /// </summary> + private ClientQueryCursorBase<T> GetFieldsCursorNoColumnNames<T>(IBinaryStream s, + Func<IBinaryRawReader, int, T> readerFunc) + { + var cursorId = s.ReadLong(); + var columnCount = s.ReadInt(); + return new ClientQueryCursorBase<T>(_ignite, cursorId, _keepBinary, s, + ClientOp.QuerySqlFieldsCursorGetPage, r => readerFunc(r, columnCount)); } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs index 5123537..5a0a1f6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Client/Cache/Query/ClientQueryCursorBase.cs @@ -26,7 +26,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache.Query /// <summary> /// Client query cursor base. /// </summary> - internal abstract class ClientQueryCursorBase<T> : QueryCursorBase<T> + internal class ClientQueryCursorBase<T> : QueryCursorBase<T> { /** Ignite. */ private readonly IgniteClient _ignite; @@ -46,7 +46,7 @@ namespace Apache.Ignite.Core.Impl.Client.Cache.Query /// <param name="initialBatchStream">Optional stream with initial batch.</param> /// <param name="getPageOp">The get page op.</param> /// <param name="readFunc">Read func.</param> - protected ClientQueryCursorBase(IgniteClient ignite, long cursorId, bool keepBinary, + public ClientQueryCursorBase(IgniteClient ignite, long cursorId, bool keepBinary, IBinaryStream initialBatchStream, ClientOp getPageOp, Func<BinaryReader, T> readFunc) : base(ignite.Marshaller, keepBinary, readFunc, initialBatchStream) { http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj index 735e4f2..fc13914 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Apache.Ignite.Linq.csproj @@ -51,7 +51,8 @@ <Reference Include="System.Core" /> </ItemGroup> <ItemGroup> - <Compile Include="CacheExtensions.cs" /> + <Compile Include="CacheClientLinqExtensions.cs" /> + <Compile Include="CacheLinqExtensions.cs" /> <Compile Include="CompiledQuery.cs" /> <Compile Include="ICacheQueryable.cs" /> <Compile Include="Impl\AliasDictionary.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs new file mode 100644 index 0000000..0c3544b --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheClientLinqExtensions.cs @@ -0,0 +1,131 @@ +/* + * 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.Linq +{ + using System.Linq; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Configuration; + using Apache.Ignite.Core.Cache.Query; + using Apache.Ignite.Core.Client.Cache; + using Apache.Ignite.Core.Impl.Cache; + using Apache.Ignite.Core.Impl.Common; + using Apache.Ignite.Linq.Impl; + + /// <summary> + /// Extensions methods for <see cref="ICacheClient{TK,TV}"/>. + /// </summary> + public static class CacheClientLinqExtensions + { + /// <summary> + /// Gets an <see cref="IQueryable{T}"/> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> + /// for introspection, or converted with <see cref="CacheLinqExtensions.ToCacheQueryable{T}"/> + /// extension method. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICacheClient<TKey, TValue> cache) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + + return AsCacheQueryable(cache, false, null); + } + + /// <summary> + /// Gets an <see cref="IQueryable{T}"/> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <param name="local">Local flag. When set query will be executed only on local node, so only local + /// entries will be returned as query result.</param> + /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICacheClient<TKey, TValue> cache, bool local) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + + return AsCacheQueryable(cache, local, null); + } + + /// <summary> + /// Gets an <see cref="IQueryable{T}" /> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <param name="local">Local flag. When set query will be executed only on local node, so only local + /// entries will be returned as query result.</param> + /// <param name="tableName"> + /// Name of the table. + /// <para /> + /// Table name is equal to short class name of a cache value. + /// When a cache has only one type of values, or only one <see cref="QueryEntity"/> defined, + /// table name will be inferred and can be omitted. + /// </param> + /// <returns><see cref="IQueryable{T}" /> instance over this cache.</returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICacheClient<TKey, TValue> cache, bool local, string tableName) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + + return AsCacheQueryable(cache, new QueryOptions {Local = local, TableName = tableName}); + } + + /// <summary> + /// Gets an <see cref="IQueryable{T}" /> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICacheClient{TK,TV}.Query(SqlFieldsQuery)"/>. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <param name="queryOptions">The query options.</param> + /// <returns> + /// <see cref="IQueryable{T}" /> instance over this cache. + /// </returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICacheClient<TKey, TValue> cache, QueryOptions queryOptions) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + IgniteArgumentCheck.NotNull(queryOptions, "queryOptions"); + + return new CacheQueryable<TKey, TValue>((ICacheInternal) cache, queryOptions); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs deleted file mode 100644 index f759dbb..0000000 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheExtensions.cs +++ /dev/null @@ -1,195 +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.Linq -{ - using System; - using System.Diagnostics.CodeAnalysis; - using System.Linq; - using System.Linq.Expressions; - using Apache.Ignite.Core.Cache; - using Apache.Ignite.Core.Cache.Configuration; - using Apache.Ignite.Core.Impl.Common; - using Apache.Ignite.Linq.Impl; - using Apache.Ignite.Linq.Impl.Dml; - - /// <summary> - /// Extensions methods for <see cref="ICache{TK,TV}"/>. - /// </summary> - public static class CacheLinqExtensions - { - /// <summary> - /// Gets an <see cref="IQueryable{T}"/> instance over this cache. - /// <para /> - /// Resulting query will be translated to cache SQL query and executed over the cache instance - /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>, - /// depending on requested result. - /// <para /> - /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection. - /// </summary> - /// <typeparam name="TKey">The type of the key.</typeparam> - /// <typeparam name="TValue">The type of the value.</typeparam> - /// <param name="cache">The cache.</param> - /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns> - public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( - this ICache<TKey, TValue> cache) - { - IgniteArgumentCheck.NotNull(cache, "cache"); - - return cache.AsCacheQueryable(false, null); - } - - /// <summary> - /// Gets an <see cref="IQueryable{T}"/> instance over this cache. - /// <para /> - /// Resulting query will be translated to cache SQL query and executed over the cache instance - /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>, - /// depending on requested result. - /// <para /> - /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection. - /// </summary> - /// <typeparam name="TKey">The type of the key.</typeparam> - /// <typeparam name="TValue">The type of the value.</typeparam> - /// <param name="cache">The cache.</param> - /// <param name="local">Local flag. When set query will be executed only on local node, so only local - /// entries will be returned as query result.</param> - /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns> - public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( - this ICache<TKey, TValue> cache, bool local) - { - IgniteArgumentCheck.NotNull(cache, "cache"); - - return cache.AsCacheQueryable(local, null); - } - - /// <summary> - /// Gets an <see cref="IQueryable{T}" /> instance over this cache. - /// <para /> - /// Resulting query will be translated to cache SQL query and executed over the cache instance - /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />, - /// depending on requested result. - /// <para /> - /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection. - /// </summary> - /// <typeparam name="TKey">The type of the key.</typeparam> - /// <typeparam name="TValue">The type of the value.</typeparam> - /// <param name="cache">The cache.</param> - /// <param name="local">Local flag. When set query will be executed only on local node, so only local - /// entries will be returned as query result.</param> - /// <param name="tableName"> - /// Name of the table. - /// <para /> - /// Table name is equal to short class name of a cache value. - /// When a cache has only one type of values, or only one <see cref="QueryEntity"/> defined, - /// table name will be inferred and can be omitted. - /// </param> - /// <returns><see cref="IQueryable{T}" /> instance over this cache.</returns> - public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( - this ICache<TKey, TValue> cache, bool local, string tableName) - { - IgniteArgumentCheck.NotNull(cache, "cache"); - - return cache.AsCacheQueryable(new QueryOptions {Local = local, TableName = tableName}); - } - - /// <summary> - /// Gets an <see cref="IQueryable{T}" /> instance over this cache. - /// <para /> - /// Resulting query will be translated to cache SQL query and executed over the cache instance - /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />, - /// depending on requested result. - /// <para /> - /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection. - /// </summary> - /// <typeparam name="TKey">The type of the key.</typeparam> - /// <typeparam name="TValue">The type of the value.</typeparam> - /// <param name="cache">The cache.</param> - /// <param name="queryOptions">The query options.</param> - /// <returns> - /// <see cref="IQueryable{T}" /> instance over this cache. - /// </returns> - public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( - this ICache<TKey, TValue> cache, QueryOptions queryOptions) - { - IgniteArgumentCheck.NotNull(cache, "cache"); - IgniteArgumentCheck.NotNull(queryOptions, "queryOptions"); - - return new CacheQueryable<TKey, TValue>(cache, queryOptions); - } - - /// <summary> - /// Casts this query to <see cref="ICacheQueryable"/>. - /// </summary> - public static ICacheQueryable ToCacheQueryable<T>(this IQueryable<T> query) - { - IgniteArgumentCheck.NotNull(query, "query"); - - return (ICacheQueryable) query; - } - - /// <summary> - /// Removes all rows that are matched by the specified query. - /// <para /> - /// This method results in "DELETE FROM" distributed SQL query, performing bulk delete - /// (as opposed to fetching all rows locally). - /// </summary> - /// <typeparam name="TKey">Key type.</typeparam> - /// <typeparam name="TValue">Value type.</typeparam> - /// <param name="query">The query.</param> - /// <returns>Affected row count.</returns> - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", - Justification = "Validation is present.")] - public static int RemoveAll<TKey, TValue>(this IQueryable<ICacheEntry<TKey, TValue>> query) - { - IgniteArgumentCheck.NotNull(query, "query"); - - var method = RemoveAllExpressionNode.RemoveAllMethodInfo.MakeGenericMethod(typeof(TKey), typeof(TValue)); - - return query.Provider.Execute<int>(Expression.Call(null, method, query.Expression)); - } - - /// <summary> - /// Deletes all rows that are matched by the specified query. - /// <para /> - /// This method results in "DELETE FROM" distributed SQL query, performing bulk delete - /// (as opposed to fetching all rows locally). - /// </summary> - /// <typeparam name="TKey">Key type.</typeparam> - /// <typeparam name="TValue">Value type.</typeparam> - /// <param name="query">The query.</param> - /// <param name="predicate">The predicate.</param> - /// <returns> - /// Affected row count. - /// </returns> - [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", - Justification = "Only specified type of predicate is valid.")] - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", - Justification = "Validation is present.")] - public static int RemoveAll<TKey, TValue>(this IQueryable<ICacheEntry<TKey, TValue>> query, - Expression<Func<ICacheEntry<TKey, TValue>, bool>> predicate) - { - IgniteArgumentCheck.NotNull(query, "query"); - IgniteArgumentCheck.NotNull(predicate, "predicate"); - - var method = RemoveAllExpressionNode.RemoveAllPredicateMethodInfo - .MakeGenericMethod(typeof(TKey), typeof(TValue)); - - return query.Provider.Execute<int>(Expression.Call(null, method, query.Expression, - Expression.Quote(predicate))); - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs new file mode 100644 index 0000000..940b23b --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/CacheLinqExtensions.cs @@ -0,0 +1,197 @@ +/* + * 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.Linq +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Linq; + using System.Linq.Expressions; + using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Configuration; + using Apache.Ignite.Core.Impl.Cache; + using Apache.Ignite.Core.Impl.Common; + using Apache.Ignite.Linq.Impl; + using Apache.Ignite.Linq.Impl.Dml; + + /// <summary> + /// Extensions methods for <see cref="ICache{TK,TV}"/>. + /// </summary> + public static class CacheLinqExtensions + { + /// <summary> + /// Gets an <see cref="IQueryable{T}"/> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>, + /// depending on requested result. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> + /// for introspection, or converted with <see cref="ToCacheQueryable{T}"/> extension method. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICache<TKey, TValue> cache) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + + return cache.AsCacheQueryable(false, null); + } + + /// <summary> + /// Gets an <see cref="IQueryable{T}"/> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICache{TK,TV}.Query"/> or <see cref="ICache{TK,TV}.QueryFields"/>, + /// depending on requested result. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable"/> for introspection. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <param name="local">Local flag. When set query will be executed only on local node, so only local + /// entries will be returned as query result.</param> + /// <returns><see cref="IQueryable{T}"/> instance over this cache.</returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICache<TKey, TValue> cache, bool local) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + + return cache.AsCacheQueryable(local, null); + } + + /// <summary> + /// Gets an <see cref="IQueryable{T}" /> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />, + /// depending on requested result. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <param name="local">Local flag. When set query will be executed only on local node, so only local + /// entries will be returned as query result.</param> + /// <param name="tableName"> + /// Name of the table. + /// <para /> + /// Table name is equal to short class name of a cache value. + /// When a cache has only one type of values, or only one <see cref="QueryEntity"/> defined, + /// table name will be inferred and can be omitted. + /// </param> + /// <returns><see cref="IQueryable{T}" /> instance over this cache.</returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICache<TKey, TValue> cache, bool local, string tableName) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + + return cache.AsCacheQueryable(new QueryOptions {Local = local, TableName = tableName}); + } + + /// <summary> + /// Gets an <see cref="IQueryable{T}" /> instance over this cache. + /// <para /> + /// Resulting query will be translated to cache SQL query and executed over the cache instance + /// via either <see cref="ICache{TK,TV}.Query" /> or <see cref="ICache{TK,TV}.QueryFields" />, + /// depending on requested result. + /// <para /> + /// Result of this method (and subsequent query) can be cast to <see cref="ICacheQueryable" /> for introspection. + /// </summary> + /// <typeparam name="TKey">The type of the key.</typeparam> + /// <typeparam name="TValue">The type of the value.</typeparam> + /// <param name="cache">The cache.</param> + /// <param name="queryOptions">The query options.</param> + /// <returns> + /// <see cref="IQueryable{T}" /> instance over this cache. + /// </returns> + public static IQueryable<ICacheEntry<TKey, TValue>> AsCacheQueryable<TKey, TValue>( + this ICache<TKey, TValue> cache, QueryOptions queryOptions) + { + IgniteArgumentCheck.NotNull(cache, "cache"); + IgniteArgumentCheck.NotNull(queryOptions, "queryOptions"); + + return new CacheQueryable<TKey, TValue>((ICacheInternal) cache, queryOptions, cache.Ignite); + } + + /// <summary> + /// Casts this query to <see cref="ICacheQueryable"/>. + /// </summary> + public static ICacheQueryable ToCacheQueryable<T>(this IQueryable<T> query) + { + IgniteArgumentCheck.NotNull(query, "query"); + + return (ICacheQueryable) query; + } + + /// <summary> + /// Removes all rows that are matched by the specified query. + /// <para /> + /// This method results in "DELETE FROM" distributed SQL query, performing bulk delete + /// (as opposed to fetching all rows locally). + /// </summary> + /// <typeparam name="TKey">Key type.</typeparam> + /// <typeparam name="TValue">Value type.</typeparam> + /// <param name="query">The query.</param> + /// <returns>Affected row count.</returns> + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", + Justification = "Validation is present.")] + public static int RemoveAll<TKey, TValue>(this IQueryable<ICacheEntry<TKey, TValue>> query) + { + IgniteArgumentCheck.NotNull(query, "query"); + + var method = RemoveAllExpressionNode.RemoveAllMethodInfo.MakeGenericMethod(typeof(TKey), typeof(TValue)); + + return query.Provider.Execute<int>(Expression.Call(null, method, query.Expression)); + } + + /// <summary> + /// Deletes all rows that are matched by the specified query. + /// <para /> + /// This method results in "DELETE FROM" distributed SQL query, performing bulk delete + /// (as opposed to fetching all rows locally). + /// </summary> + /// <typeparam name="TKey">Key type.</typeparam> + /// <typeparam name="TValue">Value type.</typeparam> + /// <param name="query">The query.</param> + /// <param name="predicate">The predicate.</param> + /// <returns> + /// Affected row count. + /// </returns> + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", + Justification = "Only specified type of predicate is valid.")] + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", + Justification = "Validation is present.")] + public static int RemoveAll<TKey, TValue>(this IQueryable<ICacheEntry<TKey, TValue>> query, + Expression<Func<ICacheEntry<TKey, TValue>, bool>> predicate) + { + IgniteArgumentCheck.NotNull(query, "query"); + IgniteArgumentCheck.NotNull(predicate, "predicate"); + + var method = RemoveAllExpressionNode.RemoveAllPredicateMethodInfo + .MakeGenericMethod(typeof(TKey), typeof(TValue)); + + return query.Provider.Execute<int>(Expression.Call(null, method, query.Expression, + Expression.Quote(predicate))); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs index ef641e2..426d52c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/ICacheQueryable.cs @@ -37,6 +37,7 @@ namespace Apache.Ignite.Linq /// <summary> /// Gets the Ignite instance associated with this query. /// </summary> + [Obsolete("Deprecated, null for thin client.")] IIgnite Ignite { get; } /// <summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs index cce89fd..4f35a42 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheFieldsQueryProvider.cs @@ -63,7 +63,6 @@ namespace Apache.Ignite.Linq.Impl { Debug.Assert(queryParser != null); Debug.Assert(executor != null); - Debug.Assert(ignite != null); Debug.Assert(cacheConfiguration != null); Debug.Assert(cacheValueType != null); @@ -85,6 +84,7 @@ namespace Apache.Ignite.Linq.Impl /// <summary> /// Gets the ignite. /// </summary> + [Obsolete("Deprecated, null for thin client, only used for ICacheQueryable.")] public IIgnite Ignite { get { return _ignite; } http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs index e271363..5148020 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryable.cs @@ -18,6 +18,7 @@ namespace Apache.Ignite.Linq.Impl { using System.Linq; + using Apache.Ignite.Core; using Apache.Ignite.Core.Cache; using Apache.Ignite.Core.Impl.Cache; @@ -31,10 +32,11 @@ namespace Apache.Ignite.Linq.Impl /// </summary> /// <param name="cache">The cache.</param> /// <param name="queryOptions">The query options.</param> - public CacheQueryable(ICache<TKey, TValue> cache, QueryOptions queryOptions) + /// <param name="ignite">The ignite.</param> + public CacheQueryable(ICacheInternal cache, QueryOptions queryOptions, IIgnite ignite = null) : base(new CacheFieldsQueryProvider(CacheQueryParser.Instance, - new CacheFieldsQueryExecutor((ICacheInternal) cache, queryOptions), - cache.Ignite, cache.GetConfiguration(), queryOptions.TableName, typeof(TValue))) + new CacheFieldsQueryExecutor(cache, queryOptions), + ignite, cache.GetConfiguration(), queryOptions.TableName, typeof(TValue))) { // No-op. } http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs index 5702f4f..c585119 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Linq/Impl/CacheQueryableBase.cs @@ -55,6 +55,7 @@ namespace Apache.Ignite.Linq.Impl } /** <inheritdoc /> */ + [Obsolete("Deprecated, null for thin client.")] public IIgnite Ignite { get { return CacheQueryProvider.Ignite; } http://git-wip-us.apache.org/repos/asf/ignite/blob/1f433752/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs b/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs index 6d8aa6b..c6660c3 100644 --- a/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs +++ b/modules/platforms/dotnet/Apache.Ignite/IgniteRunner.cs @@ -25,7 +25,6 @@ namespace Apache.Ignite using System.Threading; using Apache.Ignite.Config; using Apache.Ignite.Core; - using Apache.Ignite.Core.Impl; using Apache.Ignite.Service; /// <summary>
