Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 61 additions & 19 deletions SQLite.Net.Tests/ValueTupleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,102 @@

namespace SQLite.Net2.Tests
{
public enum TestEnumeration
{
First,
Second,
Third = 5,
}

public class TestModelWithEnumTuple
{
public (int a, TestEnumeration e) key;
}

public class TestModelWithValueTuple
{
public ValueTuple<int, string> Value { get; set; }

public bool HasReadEula { get; set; }
}

public class TestDerivedWithGenericBase : Model<(int userId, string userName)>
{
}

public class TestModelWithNamedValueTuple
{
public (int userId, string userName) Value { get; set; }

public bool HasReadEula { get; set; }
}

public class BadTupleModel
{
public (int userId, (string firstName, string lastName)) key;
}

[TestFixture]
public class ValueTupleTests : BaseTest
{
[Test]
public void CanGetSetEnumerations()
{
var db = new SQLiteConnection(TestPath.CreateTemporaryDatabase());
var mapping = db.GetMapping<TestModelWithEnumTuple>();
Assert.That(mapping.Columns.Length, Is.EqualTo(2));

var model = new TestModelWithEnumTuple();
mapping.Columns[1].SetValue(model, TestEnumeration.Second);
Assert.That(mapping.Columns[1].GetValue(model), Is.EqualTo(TestEnumeration.Second));

// Ensure we can set an integral value.
mapping.Columns[1].SetValue(model, (int)TestEnumeration.Third);
Assert.That(mapping.Columns[1].GetValue(model), Is.EqualTo(TestEnumeration.Third));

mapping.Columns[1].SetValue(model, nameof(TestEnumeration.First));
Assert.That(mapping.Columns[1].GetValue(model), Is.EqualTo(TestEnumeration.First));
}

[Test]
public void CanGetTableMappingForValueTuple()
{
var db = new SQLiteConnection(TestPath.CreateTemporaryDatabase());
var mapping1 = db.GetMapping<TestModelWithValueTuple>();
Assert.That(mapping1.Columns.Length, Is.EqualTo(3));
Assert.That(mapping1.Columns[0].Name, Is.EqualTo($"{nameof(TestModelWithValueTuple.HasReadEula)}"));
Assert.That(mapping1.Columns[1].Name, Is.EqualTo($"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithValueTuple.Value.Item1)}"));
Assert.That(mapping1.Columns[2].Name, Is.EqualTo($"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithValueTuple.Value.Item2)}"));


Assert.That(mapping1.Columns[1].Name,
Is.EqualTo($"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithValueTuple.Value.Item1)}"));
Assert.That(mapping1.Columns[2].Name,
Is.EqualTo($"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithValueTuple.Value.Item2)}"));


var mapping2 = db.GetMapping<TestModelWithNamedValueTuple>();
Assert.That(mapping2.Columns.Length, Is.EqualTo(3));
Assert.That(mapping2.Columns[0].Name, Is.EqualTo($"{nameof(TestModelWithValueTuple.HasReadEula)}"));
Assert.That(mapping2.Columns[1].Name, Is.EqualTo($"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithNamedValueTuple.Value.userId)}"));
Assert.That(mapping2.Columns[2].Name, Is.EqualTo($"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithNamedValueTuple.Value.userName)}"));
Assert.That(mapping2.Columns[1].Name,
Is.EqualTo(
$"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithNamedValueTuple.Value.userId)}"));
Assert.That(mapping2.Columns[2].Name,
Is.EqualTo(
$"{nameof(TestModelWithValueTuple.Value)}_{nameof(TestModelWithNamedValueTuple.Value.userName)}"));

var mapping3 = db.GetMapping<TestDerivedWithGenericBase>();
Assert.That(mapping3.Columns.Length, Is.EqualTo(2));
Assert.That(mapping3.Columns[0].Name, Is.EqualTo($"{nameof(TestDerivedWithGenericBase.Key)}_{nameof(TestDerivedWithGenericBase.Key.userId)}"));
Assert.That(mapping3.Columns[1].Name, Is.EqualTo($"{nameof(TestDerivedWithGenericBase.Key)}_{nameof(TestDerivedWithGenericBase.Key.userName)}"));
Assert.That(mapping3.Columns[0].Name,
Is.EqualTo(
$"{nameof(TestDerivedWithGenericBase.Key)}_{nameof(TestDerivedWithGenericBase.Key.userId)}"));
Assert.That(mapping3.Columns[1].Name,
Is.EqualTo(
$"{nameof(TestDerivedWithGenericBase.Key)}_{nameof(TestDerivedWithGenericBase.Key.userName)}"));
}

[Test]
public void CannotCreateTablesWithNestedTuples()
{
var db = new SQLiteConnection(TestPath.CreateTemporaryDatabase());
Assert.Throws<NotSupportedException>(() => db.GetMapping<BadTupleModel>());
Assert.Throws<NotSupportedException >(() => db.CreateTable<BadTupleModel>());
Assert.Throws<NotSupportedException>(() => db.CreateTable<BadTupleModel>());
}

[Test]
Expand All @@ -84,7 +125,7 @@ public void CanOrderByTupleMember()
var allEntriesDescending = db
.Table<TestModelWithValueTuple>().OrderByDescending(x => x.Value.Item1)
.ToList();

Assert.That(allEntriesDescending.Count, Is.EqualTo(2));
Assert.That(allEntriesDescending[0].Value.Item1, Is.EqualTo(2));
Assert.That(allEntriesDescending[1].Value.Item1, Is.EqualTo(1));
Expand All @@ -108,11 +149,12 @@ public void CanAccessNamedTupleElementsNotInLocalAssembly()
},
});

var items = db.Table<TestDerivedWithGenericBase>().Where(x => x.Key.userName == "test.1" && x.Key.userId == 1).ToArray();
var items = db.Table<TestDerivedWithGenericBase>()
.Where(x => x.Key.userName == "test.1" && x.Key.userId == 1).ToArray();
Assert.That(items.Length, Is.EqualTo(1));
Assert.That(items[0].Key, Is.EqualTo((1, "test.1")));
}

[Test]
public void CanOperateOnSingleLevelValueTuples()
{
Expand All @@ -133,7 +175,7 @@ public void CanOperateOnSingleLevelValueTuples()
HasReadEula = false
}
});

db.InsertAll(new[]
{
new TestModelWithNamedValueTuple
Expand All @@ -153,11 +195,11 @@ public void CanOperateOnSingleLevelValueTuples()
.First(x => x.Value.Item1 == 1);
Assert.That(valueTupleUser1.Value.Item2, Is.EqualTo("hello"));
Assert.That(valueTupleUser1.HasReadEula, Is.True);

var namedValueUser1 = db
.Table<TestModelWithNamedValueTuple>()
.First(x => x.Value.userId == 2);

Assert.That(namedValueUser1.Value.userName, Is.EqualTo("world"));
Assert.That(namedValueUser1.HasReadEula, Is.False);
}
Expand Down
37 changes: 6 additions & 31 deletions src/SQLite.Net/TableMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public TableMapping(
{
throw new NotSupportedException("Nested tuple types are not supported.");
}

cols.Add(new Column(
type,
p,
Expand Down Expand Up @@ -166,7 +166,7 @@ public class Column
{
private readonly MemberInfo _prop;
private readonly IColumnInformationProvider _infoProvider;

public Column()
{
}
Expand Down Expand Up @@ -235,32 +235,7 @@ public Column(
/// <param name="val"></param>
public void SetValue(object obj, object val)
{
var propType = _infoProvider.GetMemberType(_prop);
var typeInfo = propType.GetTypeInfo();
object valueToSet;

if (typeInfo.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
var typeCol = propType.GetTypeInfo().GenericTypeArguments;
var nullableType = typeCol[0];
var baseType = nullableType.GetTypeInfo().BaseType;
if (baseType == typeof(Enum))
{
valueToSet = AsEnumValue(obj, nullableType, val);
}
else
{
valueToSet = val;
}
}
else if (typeInfo.BaseType == typeof(Enum))
{
valueToSet = AsEnumValue(obj, propType, val);
}
else
{
valueToSet = val;
}
var valueToSet = ColumnType.BaseType == typeof(Enum) ? AsEnumValue(obj, ColumnType, val) : val;

// If we're a value tuple then we need to recreate the tuple with the new value and set that
// on the property.
Expand Down Expand Up @@ -289,14 +264,14 @@ public void SetValue(object obj, object val)

private object AsEnumValue(object obj, Type type, object? value)
{
var result = value ?? 0;
return Enum.ToObject(type, result);
var nonNullValue = value ?? 0;
return value is string s ? Enum.Parse(type, s) : Enum.ToObject(type, nonNullValue);
}

public object GetValue(object obj)
{
var result = _infoProvider.GetValue(_prop, obj);

// If we're a value tuple then we need to get the nested value in the tuple.
if (TupleElement != -1 && result is ITuple tuple)
{
Expand Down