blob: a80526da56f4a12f46061b9538dccf5cd786ea7b [file] [log] [blame]
/*
* 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 MemberCanBePrivate.Local
// ReSharper disable UnusedAutoPropertyAccessor.Local
// ReSharper disable UnusedMember.Local
namespace Apache.Ignite.Core.Tests.Cache.Query
{
using System;
using System.Linq;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache.Configuration;
using Apache.Ignite.Core.Cache.Query;
using Apache.Ignite.Core.Impl.Binary;
using NUnit.Framework;
/// <summary>
/// Tests queries with in-code configuration.
/// </summary>
public class CacheQueriesCodeConfigurationTest
{
const string CacheName = "personCache";
/// <summary>
/// Tears down the test fixture.
/// </summary>
[TearDown]
public void TearDown()
{
Ignition.StopAll(true);
}
/// <summary>
/// Tests the SQL query.
/// </summary>
[Test]
public void TestQueryEntityConfiguration()
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
BinaryConfiguration = new BinaryConfiguration(typeof(QueryPerson)),
CacheConfiguration = new[]
{
new CacheConfiguration(CacheName, new QueryEntity(typeof(int), typeof(QueryPerson))
{
TableName = "CustomTableName",
Fields = new[]
{
new QueryField("Name", typeof(string)),
new QueryField("Age", typeof(int)),
new QueryField("Birthday", typeof(DateTime)),
},
Indexes = new[]
{
new QueryIndex
{
InlineSize = 2048,
IndexType = QueryIndexType.FullText,
Fields = new[]
{
new QueryIndexField
{
IsDescending = false,
Name = "Name"
}
}
},
new QueryIndex("Age")
}
})
}
};
using (var ignite = Ignition.Start(cfg))
{
var cache = ignite.GetCache<int, QueryPerson>(CacheName);
Assert.IsNotNull(cache);
cache[1] = new QueryPerson("Arnold", 10);
cache[2] = new QueryPerson("John", 20);
#pragma warning disable 618
using (var cursor = cache.Query(new SqlQuery(typeof (QueryPerson), "age > ? and birthday < ?",
#pragma warning restore 618
10, DateTime.UtcNow)))
{
Assert.AreEqual(2, cursor.GetAll().Single().Key);
}
using (var cursor = cache.Query(new SqlFieldsQuery(
"select _key from CustomTableName where age > ? and birthday < ?", 10, DateTime.UtcNow)))
{
Assert.AreEqual(2, cursor.GetAll().Single()[0]);
}
using (var cursor = cache.Query(new TextQuery(typeof (QueryPerson), "Ar*")))
{
Assert.AreEqual(1, cursor.GetAll().Single().Key);
}
}
}
/// <summary>
/// Tests the attribute configuration.
/// </summary>
[Test]
public void TestAttributeConfiguration()
{
// ReSharper disable once ObjectCreationAsStatement
Assert.Throws<InvalidOperationException>(() => new QueryEntity(typeof (RecursiveQuery)));
var qe = new QueryEntity {ValueType = typeof(AttributeTest) };
Assert.AreEqual(typeof(AttributeTest), qe.ValueType);
var fields = qe.Fields.ToArray();
var idxField = fields.Single(x => x.Name == "IndexedField1");
CollectionAssert.AreEquivalent(new[]
{
"SqlField", "IndexedField1", "FullTextField", "Inner", "Inner.Foo",
"GroupIndex1", "GroupIndex2", "GroupIndex3"
}, fields.Select(x => x.Name));
Assert.IsTrue(fields.Single(x => x.Name == "SqlField").NotNull);
Assert.IsFalse(idxField.NotNull);
var idx = qe.Indexes.ToArray();
Assert.AreEqual(QueryIndexType.Sorted, idx[0].IndexType);
Assert.AreEqual(QueryIndexType.Sorted, idx[1].IndexType);
Assert.AreEqual(QueryIndexType.Sorted, idx[2].IndexType);
Assert.AreEqual(QueryIndexType.FullText, idx[3].IndexType);
CollectionAssert.AreEquivalent(new[] {"GroupIndex1", "GroupIndex2"}, idx[0].Fields.Select(f => f.Name));
CollectionAssert.AreEquivalent(new[] {"GroupIndex1", "GroupIndex3"}, idx[1].Fields.Select(f => f.Name));
CollectionAssert.AreEquivalent(new[] {"IndexedField1"}, idx[2].Fields.Select(f => f.Name));
CollectionAssert.AreEquivalent(new[] {"FullTextField"}, idx[3].Fields.Select(f => f.Name));
Assert.AreEqual(-1, idx[0].InlineSize);
Assert.AreEqual(-1, idx[1].InlineSize);
Assert.AreEqual(513, idx[2].InlineSize);
Assert.AreEqual(-1, idx[3].InlineSize);
Assert.AreEqual(3, idxField.Precision);
Assert.AreEqual(4, idxField.Scale);
}
/// <summary>
/// Tests the attribute configuration query.
/// </summary>
[Test]
public void TestAttributeConfigurationQuery()
{
var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
BinaryConfiguration = new BinaryConfiguration(
typeof (AttributeQueryPerson), typeof (AttributeQueryAddress))
};
using (var ignite = Ignition.Start(cfg))
{
var cache = ignite.GetOrCreateCache<int, AttributeQueryPerson>(new CacheConfiguration(CacheName,
new QueryEntity(typeof(int), typeof(AttributeQueryPerson))));
Assert.IsNotNull(cache);
cache[1] = new AttributeQueryPerson("Arnold", 10)
{
Address = new AttributeQueryAddress {Country = "USA", Street = "Pine Tree road", Zip = 1}
};
cache[2] = new AttributeQueryPerson("John", 20);
#pragma warning disable 618
using (var cursor = cache.Query(new SqlQuery(typeof(AttributeQueryPerson),
"age > ? and age < ? and birthday > ? and birthday < ?", 10, 30,
DateTime.UtcNow.AddYears(-21), DateTime.UtcNow.AddYears(-19))))
{
Assert.AreEqual(2, cursor.GetAll().Single().Key);
}
using (var cursor = cache.Query(new SqlQuery(typeof(AttributeQueryPerson), "salary > ?", 10)))
{
Assert.AreEqual(2, cursor.GetAll().Single().Key);
}
using (var cursor = cache.Query(new SqlQuery(typeof(AttributeQueryPerson), "Country = ?", "USA")))
{
Assert.AreEqual(1, cursor.GetAll().Single().Key);
}
using (var cursor = cache.Query(new SqlQuery(typeof(AttributeQueryPerson), "Zip = ?", 1)))
{
Assert.AreEqual(1, cursor.GetAll().Single().Key);
}
#pragma warning restore 618
using (var cursor = cache.Query(new TextQuery(typeof(AttributeQueryPerson), "Ar*")))
{
Assert.AreEqual(1, cursor.GetAll().Single().Key);
}
using (var cursor = cache.Query(new TextQuery(typeof(AttributeQueryPerson), "Pin*")))
{
Assert.AreEqual(1, cursor.GetAll().Single().Key);
}
}
}
/// <summary>
/// Tests query entity validation when no <see cref="QuerySqlFieldAttribute"/> has been set.
/// </summary>
[Test]
public void TestQueryEntityValidationWithMissingQueryAttributes()
{
using (var ignite = Ignition.Start(TestUtils.GetTestConfiguration()))
{
var cfg = new CacheConfiguration(
TestUtils.TestName,
new QueryEntity(typeof(string), typeof(MissingAttributesTest)));
var cache = ignite.GetOrCreateCache<string, MissingAttributesTest>(cfg);
cache["1"] = new MissingAttributesTest {Foo = "Bar"};
}
}
/// <summary>
/// Tests that key and value types can be generic.
/// </summary>
[Test]
public void TestGenericQueryTypes()
{
var ignite = Ignition.Start(TestUtils.GetTestConfiguration());
var cfg = new CacheConfiguration(TestUtils.TestName)
{
QueryEntities = new[] {new QueryEntity(typeof(GenericTest<int>), typeof(GenericTest2<string>))}
};
var cache = ignite.GetOrCreateCache<GenericTest<int>, GenericTest2<string>>(cfg);
var key = new GenericTest<int>(1);
var value = new GenericTest2<string>("foo");
cache[key] = value;
var binType = ignite.GetBinary().GetBinaryType(value.GetType());
var expectedTypeName = BinaryBasicNameMapper.FullNameInstance.GetTypeName(value.GetType().FullName);
var expectedTypeId = BinaryUtils.GetStringHashCodeLowerCase(expectedTypeName);
Assert.AreEqual(expectedTypeName, binType.TypeName);
Assert.AreEqual(expectedTypeId, binType.TypeId);
var queryEntity = cache.GetConfiguration().QueryEntities.Single();
Assert.AreEqual(expectedTypeName, queryEntity.ValueTypeName);
var sqlRes = cache.Query(new SqlFieldsQuery("SELECT Foo, Bar from GENERICTEST2")).Single();
Assert.AreEqual(key.Foo, sqlRes[0]);
Assert.AreEqual(value.Bar, sqlRes[1]);
}
/// <summary>
/// Tests that query types can be nested generic.
/// </summary>
[Test]
public void TestNestedGenericQueryTypes()
{
var ignite = Ignition.Start(TestUtils.GetTestConfiguration());
var cfg = new CacheConfiguration(TestUtils.TestName)
{
QueryEntities = new[] {new QueryEntity(typeof(int), typeof(GenericTest<GenericTest2<string>>))}
};
var cache = ignite.GetOrCreateCache<int, GenericTest<GenericTest2<string>>>(cfg);
var value = new GenericTest<GenericTest2<string>>(new GenericTest2<string>("foobar"));
cache[1] = value;
var sqlRes = cache.Query(new SqlFieldsQuery("SELECT Bar from GENERICTEST")).Single().Single();
Assert.AreEqual(value.Foo.Bar, sqlRes);
var valTypeName = value.GetType().FullName;
Assert.IsNotNull(valTypeName);
}
/// <summary>
/// Class without any <see cref="QuerySqlFieldAttribute"/> attributes.
/// </summary>
private class MissingAttributesTest
{
/** */
public string Foo { get; set; }
}
/// <summary>
/// Test person.
/// </summary>
private class AttributeQueryPerson
{
/// <summary>
/// Initializes a new instance of the <see cref="AttributeQueryPerson"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="age">The age.</param>
public AttributeQueryPerson(string name, int age)
{
Name = name;
Age = age;
Salary = age;
Birthday = DateTime.UtcNow.AddYears(-age);
}
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
[QueryTextField(Name = "Name")]
public string Name { get; set; }
/// <summary>
/// Gets or sets the age.
/// </summary>
/// <value>
/// The age.
/// </value>
[QuerySqlField]
public int Age { get; set; }
/// <summary>
/// Gets or sets the address.
/// </summary>
/// <value>
/// The address.
/// </value>
[QuerySqlField]
public AttributeQueryAddress Address { get; set; }
/// <summary>
/// Gets or sets the salary.
/// </summary>
[QuerySqlField]
public decimal? Salary { get; set; }
/// <summary>
/// Gets or sets the birthday.
/// </summary>
[QuerySqlField]
public DateTime Birthday { get; set; }
}
/// <summary>
/// Address.
/// </summary>
private class AttributeQueryAddress
{
/// <summary>
/// Gets or sets the country.
/// </summary>
/// <value>
/// The country.
/// </value>
[QuerySqlField]
public string Country { get; set; }
/// <summary>
/// Gets or sets the zip.
/// </summary>
/// <value>
/// The zip.
/// </value>
[QuerySqlField(IsIndexed = true)]
public int Zip { get; set; }
/// <summary>
/// Gets or sets the street.
/// </summary>
/// <value>
/// The street.
/// </value>
[QueryTextField]
public string Street { get; set; }
}
/// <summary>
/// Query.
/// </summary>
private class RecursiveQuery
{
/// <summary>
/// Gets or sets the inner.
/// </summary>
/// <value>
/// The inner.
/// </value>
[QuerySqlField]
public RecursiveQuery Inner { get; set; }
}
/// <summary>
/// Attribute test class.
/// </summary>
private class AttributeTest
{
[QuerySqlField(NotNull = true)]
public double SqlField { get; set; }
[QuerySqlField(IsIndexed = true, Name = "IndexedField1", IsDescending = true, IndexInlineSize = 513,
DefaultValue = 42, Precision = 3, Scale = 4)]
public int IndexedField { get; set; }
[QueryTextField]
public string FullTextField { get; set; }
[QuerySqlField]
public AttributeTestInner Inner { get; set; }
[QuerySqlField(IsIndexed = true, IndexGroups = new[] {"group1", "group2"})]
public string GroupIndex1 { get; set; }
[QuerySqlField(IsIndexed = true, IndexGroups = new[] {"group1"})]
public string GroupIndex2 { get; set; }
[QuerySqlField(IsIndexed = true, IndexGroups = new[] {"group2"})]
public string GroupIndex3 { get; set; }
}
/// <summary>
/// Inner class.
/// </summary>
private class AttributeTestInner
{
/// <summary>
/// Gets or sets the foo.
/// </summary>
/// <value>
/// The foo.
/// </value>
[QuerySqlField]
public string Foo { get; set; }
}
/// <summary>
/// Generic query type.
/// </summary>
private class GenericTest<T>
{
/** */
public GenericTest(T foo)
{
Foo = foo;
}
/** */
[QuerySqlField]
public T Foo { get; set; }
}
/// <summary>
/// Generic query type.
/// </summary>
private class GenericTest2<T>
{
/** */
public GenericTest2(T bar)
{
Bar = bar;
}
/** */
[QuerySqlField]
public T Bar { get; set; }
}
}
}