From ec5527a51eb4c5b0e29bcba58aa14e4ab12ba81c Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 9 Aug 2016 16:53:01 +0200 Subject: [PATCH 1/5] - Added OrderByRand (SQLite RANDOM() function) option - Added SelectColumns option for usage in specifically selecting columns and arbitrary commands in SELECT statement - Added IEnumerable.Select case handling in Where Expression - Added broader "Constraint" detailed error result handling - Added tests for above features - Changed several of TableQuery's fields accessibility to protected --- .../PreparedSqlLiteInsertCommand.cs | 6 + src/SQLite.Net/TableQuery.cs | 243 +++++++++++++----- tests/ExpressionTests.cs | 24 +- tests/OrderByTests.cs | 89 +++++++ .../SQLite.Net.Tests.Generic.csproj | 45 +++- .../SQLite.Net.Tests.OSX.csproj | 46 +++- .../SQLite.Net.Tests.Win32.csproj | 44 +++- .../SQLite.Net.Tests.WinRT.csproj | 46 +++- .../SQLite.Net.Tests.WindowsPhone8.csproj | 46 +++- .../SQLite.Net.Tests.XamarinAndroid.csproj | 46 +++- ...SQLite.Net.Tests.XamarinIOS.Unified.csproj | 46 +++- .../SQLite.Net.Tests.XamarinIOS.csproj | 46 +++- tests/SelectTests.cs | 26 +- 13 files changed, 684 insertions(+), 69 deletions(-) create mode 100644 tests/OrderByTests.cs diff --git a/src/SQLite.Net/PreparedSqlLiteInsertCommand.cs b/src/SQLite.Net/PreparedSqlLiteInsertCommand.cs index 3afee874a..60e7fb43a 100644 --- a/src/SQLite.Net/PreparedSqlLiteInsertCommand.cs +++ b/src/SQLite.Net/PreparedSqlLiteInsertCommand.cs @@ -110,6 +110,12 @@ public int ExecuteNonQuery(object[] source) sqlitePlatform.SQLiteApi.Reset(Statement); throw NotNullConstraintViolationException.New(r, sqlitePlatform.SQLiteApi.Errmsg16(Connection.Handle)); } + + else if (r == Result.Constraint) + { + sqlitePlatform.SQLiteApi.Reset(Statement); + throw SQLiteException.New(r, sqlitePlatform.SQLiteApi.Errmsg16(Connection.Handle)); + } sqlitePlatform.SQLiteApi.Reset(Statement); throw SQLiteException.New(r, r.ToString()); diff --git a/src/SQLite.Net/TableQuery.cs b/src/SQLite.Net/TableQuery.cs index 96c4f989a..4486f983a 100644 --- a/src/SQLite.Net/TableQuery.cs +++ b/src/SQLite.Net/TableQuery.cs @@ -26,6 +26,7 @@ using System.Globalization; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using System.Text; using JetBrains.Annotations; using SQLite.Net.Interop; @@ -34,19 +35,21 @@ namespace SQLite.Net { public class TableQuery : BaseTableQuery, IEnumerable { - private readonly ISQLitePlatform _sqlitePlatform; - private bool _deferred; - private BaseTableQuery _joinInner; - private Expression _joinInnerKeySelector; - private BaseTableQuery _joinOuter; - private Expression _joinOuterKeySelector; - private Expression _joinSelector; - private int? _limit; - private int? _offset; - private List _orderBys; - private Expression _where; - - private TableQuery(ISQLitePlatform platformImplementation, SQLiteConnection conn, TableMapping table) + protected readonly ISQLitePlatform _sqlitePlatform; + protected bool _deferred; + protected string _select = "*"; + protected BaseTableQuery _joinInner; + protected Expression _joinInnerKeySelector; + protected BaseTableQuery _joinOuter; + protected Expression _joinOuterKeySelector; + protected Expression _joinSelector; + protected int? _limit; + protected int? _offset; + protected List _orderBys; + protected bool _orderByRand; + protected Expression _where; + + protected TableQuery(ISQLitePlatform platformImplementation, SQLiteConnection conn, TableMapping table) { _sqlitePlatform = platformImplementation; Connection = conn; @@ -61,21 +64,49 @@ public TableQuery(ISQLitePlatform platformImplementation, SQLiteConnection conn) Table = Connection.GetMapping(typeof (T)); } + /// + /// Copy constructor + /// + /// Instance to copy + protected TableQuery(TableQuery other) + : this(other._sqlitePlatform, other.Connection, other.Table) + { + _where = other._where; + _select = other._select; + _deferred = other._deferred; + _limit = other._limit; + _offset = other._offset; + _joinInner = other._joinInner; + _joinInnerKeySelector = other._joinInnerKeySelector; + _joinOuter = other._joinOuter; + _joinOuterKeySelector = other._joinOuterKeySelector; + _joinSelector = other._joinSelector; + _orderByRand = other._orderByRand; + _orderBys = other._orderBys == null + ? null + : new List(other._orderBys); + } + [PublicAPI] public SQLiteConnection Connection { get; private set; } [PublicAPI] public TableMapping Table { get; private set; } + + private IEnumerable GetEnumerable() + { + if (!_deferred) + return GenerateCommand(_select) + .ExecuteQuery(); + + return GenerateCommand(_select) + .ExecuteDeferredQuery(); + } [PublicAPI] public IEnumerator GetEnumerator() { - if (!_deferred) - { - return GenerateCommand("*").ExecuteQuery().GetEnumerator(); - } - - return GenerateCommand("*").ExecuteDeferredQuery().GetEnumerator(); + return GetEnumerable().GetEnumerator(); } [PublicAPI] @@ -85,23 +116,47 @@ IEnumerator IEnumerable.GetEnumerator() } [PublicAPI] - public TableQuery Clone() - { - return new TableQuery(_sqlitePlatform, Connection, Table) - { - _where = _where, - _deferred = _deferred, - _limit = _limit, - _offset = _offset, - _joinInner = _joinInner, - _joinInnerKeySelector = _joinInnerKeySelector, - _joinOuter = _joinOuter, - _joinOuterKeySelector = _joinOuterKeySelector, - _joinSelector = _joinSelector, - _orderBys = _orderBys == null ? null : new List(_orderBys) - }; + public IEnumerable MapTo( + bool selectFromAvailableProperties = true) + { + if (selectFromAvailableProperties) + SelectColumns(_sqlitePlatform.ReflectionService + .GetPublicInstanceProperties(typeof(U)) + .Select(prop => prop.Name) + .ToArray()); + + return GetEnumerable(); + } + + [PublicAPI] + public virtual object Clone() + { + return new TableQuery(this); } + // Alex 13/07/16 + // Should this get removed ? + + //[PublicAPI] + //public TableQuery Clone() + //{ + // return new TableQuery(_sqlitePlatform, Connection, Table) + // { + // _where = _where, + // _select = _select, + // _deferred = _deferred, + // _limit = _limit, + // _offset = _offset, + // _joinInner = _joinInner, + // _joinInnerKeySelector = _joinInnerKeySelector, + // _joinOuter = _joinOuter, + // _joinOuterKeySelector = _joinOuterKeySelector, + // _joinSelector = _joinSelector, + // _orderByRand = _orderByRand, + // _orderBys = _orderBys == null ? null : new List(_orderBys) + // }; + //} + [PublicAPI] public TableQuery Where([NotNull] Expression> predExpr) { @@ -115,7 +170,7 @@ public TableQuery Where([NotNull] Expression> predExpr) } var lambda = (LambdaExpression) predExpr; var pred = lambda.Body; - var q = Clone(); + var q = (TableQuery)Clone(); q.AddWhere(pred); return q; } @@ -123,7 +178,7 @@ public TableQuery Where([NotNull] Expression> predExpr) [PublicAPI] public TableQuery Take(int n) { - var q = Clone(); + var q = (TableQuery)Clone(); // If there is already a limit then the limit will be the minimum // of the current limit and n. @@ -171,7 +226,7 @@ public int Delete([NotNull] Expression> predExpr) [PublicAPI] public TableQuery Skip(int n) { - var q = Clone(); + var q = (TableQuery)Clone(); q._offset = n + (q._offset ?? 0); return q; @@ -186,7 +241,7 @@ public T ElementAt(int index) [PublicAPI] public TableQuery Deferred() { - var q = Clone(); + var q = (TableQuery)Clone(); q._deferred = true; return q; } @@ -215,6 +270,18 @@ public TableQuery ThenByDescending(Expression> orderE return AddOrderBy(orderExpr, false); } + public TableQuery OrderByRand() + { + if (_orderBys != null) + throw new InvalidOperationException( + "Cannot concomitantly order by Random AND column(s)"); + + var q = (TableQuery)Clone(); + q._orderByRand = true; + + return q; + } + private TableQuery AddOrderBy([NotNull] Expression> orderExpr, bool asc) { if (orderExpr == null) @@ -225,6 +292,10 @@ private TableQuery AddOrderBy([NotNull] Expression> o { throw new NotSupportedException("Must be a predicate"); } + if (_orderByRand) + throw new InvalidOperationException( + "Cannot concomitantly order by Random AND column(s)"); + var lambda = (LambdaExpression) orderExpr; MemberExpression mem; @@ -243,7 +314,7 @@ private TableQuery AddOrderBy([NotNull] Expression> o { throw new NotSupportedException("Order By does not support: " + orderExpr); } - var q = Clone(); + var q = (TableQuery)Clone(); if (q._orderBys == null) { q._orderBys = new List(); @@ -295,6 +366,40 @@ public TableQuery Join( return q; } + public TableQuery SelectColumns(params string[] propertiesName) + { + int i = 0; + string selectSqlStatement = ""; + + for (; i < propertiesName.Length - 1; i++) + selectSqlStatement += "`{" + i + "}`, "; + + return SelectColumns(selectSqlStatement + "`{" + i + "}`", propertiesName); + } + + public TableQuery SelectColumns(string selectSqlStatement, + params string[] propertiesName) + { + var q = (TableQuery)Clone(); + + for (int i = 0; i < propertiesName.Length; i++) + { + TableMapping.Column column = Table.FindColumnWithPropertyName( + propertiesName[i] as string); + + if (column == null) + throw new ArgumentException( + "No such column " + propertiesName[i], + nameof(propertiesName)); + + propertiesName[i] = column.Name; + } + + q._select = String.Format(selectSqlStatement, propertiesName); + + return q; + } + private SQLiteCommand GenerateCommand([NotNull] string selectionList) { if (selectionList == null) @@ -305,19 +410,25 @@ private SQLiteCommand GenerateCommand([NotNull] string selectionList) { throw new NotSupportedException("Joins are not supported."); } + var cmdText = "select " + selectionList + " from \"" + Table.TableName + "\""; + var args = new List(); if (_where != null) { var w = CompileExpr(_where, args); cmdText += " where " + w.CommandText; } + if ((_orderBys != null) && (_orderBys.Count > 0)) { var t = string.Join(", ", _orderBys.Select(o => "\"" + o.ColumnName + "\"" + (o.Ascending ? "" : " desc")).ToArray()); cmdText += " order by " + t; } + else if (_orderByRand) + cmdText += " order by RANDOM() "; + if (_limit.HasValue) { cmdText += " limit " + _limit.Value; @@ -386,6 +497,15 @@ private CompileResult CompileExpr([NotNull] Expression expr, List queryA var args = new CompileResult[call.Arguments.Count]; var obj = call.Object != null ? CompileExpr(call.Object, queryArgs) : null; + if (call.Method.Name == "Select" && args.Length == 2) + { + object val = Expression.Lambda(call) + .Compile() + .DynamicInvoke(); + + return CompileEnumerable(val, queryArgs); + } + for (var i = 0; i < args.Length; i++) { args[i] = CompileExpr(call.Arguments[i], queryArgs); @@ -506,33 +626,38 @@ private CompileResult CompileExpr([NotNull] Expression expr, List queryA // // Work special magic for enumerables // - if (val != null && val is IEnumerable && !(val is string) && !(val is IEnumerable)) + return CompileEnumerable(val, queryArgs); + } + throw new NotSupportedException("Cannot compile: " + expr.NodeType); + } + + private CompileResult CompileEnumerable(object val, List queryArgs) + { + if (val != null && val is IEnumerable && !(val is string) && !(val is IEnumerable)) + { + var sb = new StringBuilder(); + sb.Append("("); + var head = ""; + foreach (var a in (IEnumerable)val) { - var sb = new StringBuilder(); - sb.Append("("); - var head = ""; - foreach (var a in (IEnumerable) val) - { - queryArgs.Add(a); - sb.Append(head); - sb.Append("?"); - head = ","; - } - sb.Append(")"); - return new CompileResult - { - CommandText = sb.ToString(), - Value = val - }; + queryArgs.Add(a); + sb.Append(head); + sb.Append("?"); + head = ","; } - queryArgs.Add(val); + sb.Append(")"); return new CompileResult { - CommandText = "?", + CommandText = sb.ToString(), Value = val }; } - throw new NotSupportedException("Cannot compile: " + expr.NodeType); + queryArgs.Add(val); + return new CompileResult + { + CommandText = "?", + Value = val + }; } [CanBeNull] diff --git a/tests/ExpressionTests.cs b/tests/ExpressionTests.cs index 81d1b0f41..26e5d2526 100644 --- a/tests/ExpressionTests.cs +++ b/tests/ExpressionTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using SQLite.Net.Attributes; @@ -10,7 +11,7 @@ public class ExpressionTests [Table("AGoodTableName")] private class TestTable { - [PrimaryKey] + [PrimaryKey, AutoIncrement] public int Id { get; set; } public string Name { get; set; } @@ -50,5 +51,26 @@ public void ToUpper() Assert.AreEqual(1, x.Count()); } + + [Test] + public void Select() + { + var db = new TestDb(); + + db.CreateTable(); + + List tests = new List(); + + for (int i = 0; i < 10; i++) + tests.Add(new TestTable { Name = "test" + i }); + + db.InsertAll(tests); + + var x = db.Table().Where( + t => + tests.Select(t2 => t2.Name).Contains(t.Name)); + + Assert.AreEqual(tests.Count, x.Count()); + } } } \ No newline at end of file diff --git a/tests/OrderByTests.cs b/tests/OrderByTests.cs new file mode 100644 index 000000000..64306f240 --- /dev/null +++ b/tests/OrderByTests.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using SQLite.Net.Async; +using SQLite.Net.Attributes; + +namespace SQLite.Net.Tests +{ + + + /// + /// Defines tests that exercise async behaviour. + /// + [TestFixture] + public class OrderByTest + { + public class TestObj + { + [AutoIncrement, PrimaryKey] + public int Id { get; set; } + + public override string ToString() + { + return string.Format("[TestObj: Id={0}]", Id); + } + + public override bool Equals(Object obj) + { + return Id == (obj as TestObj)?.Id; + } + + protected bool Equals(TestObj other) + { + return Id == other.Id; + } + + public override int GetHashCode() + { + return Id; + } + } + + public class TestDb : SQLiteConnection + { + public TestDb(String path) + : base(new SQLitePlatformTest(), path) + { + CreateTable(); + } + } + + [Test] + public void OrderByWorks() + { + using (var db = new TestDb(TestPath.CreateTemporaryDatabase())) + { + TestObj testObj = new TestObj(); + TestObj[] testObjects = new TestObj[100]; + + for (int i = 0; i < testObjects.Length; i++) + testObjects[i] = testObj; + + db.InsertAll(testObjects); + + try + { + CollectionAssert.AreEqual( + db.Table().OrderBy(k => k.Id), + db.Table().OrderBy(k => k.Id)); + CollectionAssert.AreNotEqual( + db.Table().OrderBy(k => k.Id), + db.Table().OrderByDescending(k => k.Id)); + CollectionAssert.AreNotEqual( + db.Table().OrderByRand(), + db.Table().OrderByRand()); + } + catch (NotImplementedException) + { + //Allow Not implemented exceptions as the selection may be too complex. + } + } + + } + } +} \ No newline at end of file diff --git a/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj b/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj index bdfba89a6..d81c927a6 100644 --- a/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj +++ b/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj @@ -61,7 +61,50 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs diff --git a/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj b/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj index af966781c..b9f9bfd34 100644 --- a/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj +++ b/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj @@ -58,7 +58,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs + diff --git a/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj b/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj index e7cfc5934..57d16df6b 100644 --- a/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj +++ b/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj @@ -79,7 +79,49 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj b/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj index e17ae1e5a..652eca52d 100644 --- a/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj +++ b/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj @@ -120,7 +120,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs + diff --git a/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj b/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj index af129e4a9..9706aed0b 100644 --- a/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj +++ b/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj @@ -74,7 +74,51 @@ 4 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs + App.xaml diff --git a/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj b/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj index d74b87cef..744aae6de 100644 --- a/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj +++ b/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj @@ -69,7 +69,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs + diff --git a/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj b/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj index d16524820..c898bf6c5 100644 --- a/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj +++ b/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj @@ -123,7 +123,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs + diff --git a/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj b/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj index fdea96c5d..45c4445d5 100644 --- a/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj +++ b/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj @@ -73,7 +73,51 @@ iPhone Distribution - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OrderByTests.cs + diff --git a/tests/SelectTests.cs b/tests/SelectTests.cs index 073048d5c..86f2c3619 100644 --- a/tests/SelectTests.cs +++ b/tests/SelectTests.cs @@ -31,6 +31,11 @@ public override string ToString() } } + class TestMappedObj + { + public int Id { get; set; } + } + public class TestDb : SQLiteConnection { public TestDb(String path) @@ -54,8 +59,27 @@ public void SelectWorks() { //Allow Not implemented exceptions as the selection may be too complex. } + + Assert.That( + db.Table() + .SelectColumns("`{0}` * 2 as `Order`", nameof(TestObj.Order)) + .Select(obj => obj.Order).First(), + Is.EqualTo(10)); } - + } + + [Test] + public void SelectMapping() + { + using (var db = new TestDb(TestPath.CreateTemporaryDatabase())) + { + db.Insert(new TestObj() { Order = 5 }); + + Assert.That( + db.Table().MapTo().First().Id, + Is.GreaterThan(0)); + } + } } } \ No newline at end of file From 392dfda35d376646b9799d066679f74993671426 Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 2 Sep 2016 16:29:15 +0200 Subject: [PATCH 2/5] - Fixed undesired changes in tests .csproj (individual .cs items => back to *.cs ) - Fixed AppVeyor compile error - Fixed CollectionAssert error - Added GetTableName to IColumnInformationProvider -- TableAttribute was not proxied through the provider, is this on purpose or a simple omission ? --- .../DefaultColumnInformationProvider.cs | 12 ++++- .../Attributes/IColumnInformationProvider.cs | 1 + src/SQLite.Net/TableMapping.cs | 5 +- src/SQLite.Net/TableQuery.cs | 2 +- tests/DefaulAttributeTest.cs | 7 ++- tests/IgnoreTest.cs | 7 ++- tests/OrderByTests.cs | 38 ++++++++++++--- .../SQLite.Net.Tests.Generic.csproj | 45 +----------------- .../SQLite.Net.Tests.OSX.csproj | 46 +------------------ .../SQLite.Net.Tests.Win32.csproj | 44 +----------------- .../SQLite.Net.Tests.WinRT.csproj | 46 +------------------ .../SQLite.Net.Tests.WindowsPhone8.csproj | 46 +------------------ .../Resources/Resource.designer.cs | 2 + .../SQLite.Net.Tests.XamarinAndroid.csproj | 46 +------------------ ...SQLite.Net.Tests.XamarinIOS.Unified.csproj | 46 +------------------ .../SQLite.Net.Tests.XamarinIOS.csproj | 46 +------------------ 16 files changed, 67 insertions(+), 372 deletions(-) diff --git a/src/SQLite.Net/Attributes/DefaultColumnInformationProvider.cs b/src/SQLite.Net/Attributes/DefaultColumnInformationProvider.cs index cb8711900..55e144197 100644 --- a/src/SQLite.Net/Attributes/DefaultColumnInformationProvider.cs +++ b/src/SQLite.Net/Attributes/DefaultColumnInformationProvider.cs @@ -12,11 +12,19 @@ public class DefaultColumnInformationProvider : IColumnInformationProvider public string GetColumnName(PropertyInfo p) { - var colAttr = p.GetCustomAttributes(true).FirstOrDefault(); + var colAttr = + p.GetCustomAttributes(true).FirstOrDefault(); return colAttr == null ? p.Name : colAttr.Name; } - public bool IsIgnored(PropertyInfo p) + public string GetTableName(TypeInfo t) + { + var tableAttr = + t.GetCustomAttributes(true).FirstOrDefault(); + return tableAttr == null ? t.Name : tableAttr.Name; + } + + public bool IsIgnored(PropertyInfo p) { return p.IsDefined(typeof (IgnoreAttribute), true); } diff --git a/src/SQLite.Net/Attributes/IColumnInformationProvider.cs b/src/SQLite.Net/Attributes/IColumnInformationProvider.cs index 75cd8f65b..3a9abb18f 100644 --- a/src/SQLite.Net/Attributes/IColumnInformationProvider.cs +++ b/src/SQLite.Net/Attributes/IColumnInformationProvider.cs @@ -15,6 +15,7 @@ public interface IColumnInformationProvider bool IsMarkedNotNull(MemberInfo p); bool IsIgnored(PropertyInfo p); string GetColumnName(PropertyInfo p); + string GetTableName(TypeInfo t); } } diff --git a/src/SQLite.Net/TableMapping.cs b/src/SQLite.Net/TableMapping.cs index 86b49a035..0c5740f7b 100644 --- a/src/SQLite.Net/TableMapping.cs +++ b/src/SQLite.Net/TableMapping.cs @@ -44,10 +44,7 @@ public TableMapping(Type type, IEnumerable properties, CreateFlags } MappedType = type; - - var tableAttr = type.GetTypeInfo().GetCustomAttributes().FirstOrDefault(); - - TableName = tableAttr != null ? tableAttr.Name : MappedType.Name; + TableName = infoProvider.GetTableName(MappedType.GetTypeInfo()); var props = properties; diff --git a/src/SQLite.Net/TableQuery.cs b/src/SQLite.Net/TableQuery.cs index 4486f983a..9308d1774 100644 --- a/src/SQLite.Net/TableQuery.cs +++ b/src/SQLite.Net/TableQuery.cs @@ -390,7 +390,7 @@ public TableQuery SelectColumns(string selectSqlStatement, if (column == null) throw new ArgumentException( "No such column " + propertiesName[i], - nameof(propertiesName)); + "propertiesName"); propertiesName[i] = column.Name; } diff --git a/tests/DefaulAttributeTest.cs b/tests/DefaulAttributeTest.cs index 9d308cf3c..73af4f161 100644 --- a/tests/DefaulAttributeTest.cs +++ b/tests/DefaulAttributeTest.cs @@ -77,7 +77,12 @@ public string GetColumnName(PropertyInfo p) return p.Name; } - public bool IsIgnored(PropertyInfo p) + public string GetTableName(TypeInfo t) + { + return t.Name; + } + + public bool IsIgnored(PropertyInfo p) { return false; } diff --git a/tests/IgnoreTest.cs b/tests/IgnoreTest.cs index 8f1a26c3e..ab48bef15 100644 --- a/tests/IgnoreTest.cs +++ b/tests/IgnoreTest.cs @@ -33,7 +33,12 @@ public string GetColumnName(PropertyInfo p) return p.Name; } - public bool IsIgnored(PropertyInfo p) + public string GetTableName(TypeInfo t) + { + return t.Name; + } + + public bool IsIgnored(PropertyInfo p) { return p.IsDefined(typeof (TestIgnoreAttribute), true); } diff --git a/tests/OrderByTests.cs b/tests/OrderByTests.cs index 64306f240..afb7172f2 100644 --- a/tests/OrderByTests.cs +++ b/tests/OrderByTests.cs @@ -68,22 +68,48 @@ public void OrderByWorks() try { - CollectionAssert.AreEqual( + AssertCollectionContent( db.Table().OrderBy(k => k.Id), db.Table().OrderBy(k => k.Id)); - CollectionAssert.AreNotEqual( + AssertCollectionContent( db.Table().OrderBy(k => k.Id), - db.Table().OrderByDescending(k => k.Id)); - CollectionAssert.AreNotEqual( + db.Table().OrderByDescending(k => k.Id), + true); + AssertCollectionContent( db.Table().OrderByRand(), - db.Table().OrderByRand()); + db.Table().OrderByRand(), + true); } catch (NotImplementedException) { //Allow Not implemented exceptions as the selection may be too complex. } } - + } + + private void AssertCollectionContent( + IEnumerable col1, IEnumerable col2, bool negate = false) + { + Assert.AreEqual(col1.Count(), col2.Count()); + + var enumerator1 = col1.GetEnumerator(); + var enumerator2 = col2.GetEnumerator(); + + while (enumerator1.MoveNext() && enumerator2.MoveNext()) + { + T item1 = enumerator1.Current; + T item2 = enumerator2.Current; + + if (negate) + { + Assert.AreNotEqual(item1, item2); + + // Only one comparison suffice to assert condition true + break; + } + + Assert.AreEqual(item1, item2); + } } } } \ No newline at end of file diff --git a/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj b/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj index d81c927a6..bdfba89a6 100644 --- a/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj +++ b/tests/SQLite.Net.Tests.Generic/SQLite.Net.Tests.Generic.csproj @@ -61,50 +61,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs + diff --git a/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj b/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj index b9f9bfd34..af966781c 100644 --- a/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj +++ b/tests/SQLite.Net.Tests.OSX/SQLite.Net.Tests.OSX.csproj @@ -58,51 +58,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs - + diff --git a/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj b/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj index 57d16df6b..e7cfc5934 100644 --- a/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj +++ b/tests/SQLite.Net.Tests.Win32/SQLite.Net.Tests.Win32.csproj @@ -79,49 +79,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj b/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj index 652eca52d..e17ae1e5a 100644 --- a/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj +++ b/tests/SQLite.Net.Tests.WinRT/SQLite.Net.Tests.WinRT.csproj @@ -120,51 +120,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs - + diff --git a/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj b/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj index 9706aed0b..af129e4a9 100644 --- a/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj +++ b/tests/SQLite.Net.Tests.WindowsPhone8/SQLite.Net.Tests.WindowsPhone8.csproj @@ -74,51 +74,7 @@ 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs - + App.xaml diff --git a/tests/SQLite.Net.Tests.XamarinAndroid/Resources/Resource.designer.cs b/tests/SQLite.Net.Tests.XamarinAndroid/Resources/Resource.designer.cs index bc99d2a2e..afa804f4b 100644 --- a/tests/SQLite.Net.Tests.XamarinAndroid/Resources/Resource.designer.cs +++ b/tests/SQLite.Net.Tests.XamarinAndroid/Resources/Resource.designer.cs @@ -28,6 +28,8 @@ public static void UpdateIdValues() { global::PCLStorage.Resource.String.ApplicationName = global::SQLite.Net.Tests.XamarinAndroid.Resource.String.ApplicationName; global::PCLStorage.Resource.String.Hello = global::SQLite.Net.Tests.XamarinAndroid.Resource.String.Hello; + global::SQLite.Net.Platform.XamarinAndroid.Resource.String.ApplicationName = global::SQLite.Net.Tests.XamarinAndroid.Resource.String.ApplicationName; + global::SQLite.Net.Platform.XamarinAndroid.Resource.String.Hello = global::SQLite.Net.Tests.XamarinAndroid.Resource.String.Hello; global::Xamarin.Android.NUnitLite.Resource.Id.OptionHostName = global::SQLite.Net.Tests.XamarinAndroid.Resource.Id.OptionHostName; global::Xamarin.Android.NUnitLite.Resource.Id.OptionPort = global::SQLite.Net.Tests.XamarinAndroid.Resource.Id.OptionPort; global::Xamarin.Android.NUnitLite.Resource.Id.OptionRemoteServer = global::SQLite.Net.Tests.XamarinAndroid.Resource.Id.OptionRemoteServer; diff --git a/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj b/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj index 744aae6de..d74b87cef 100644 --- a/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj +++ b/tests/SQLite.Net.Tests.XamarinAndroid/SQLite.Net.Tests.XamarinAndroid.csproj @@ -69,51 +69,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs - + diff --git a/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj b/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj index c898bf6c5..d16524820 100644 --- a/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj +++ b/tests/SQLite.Net.Tests.XamarinIOS.Unified/SQLite.Net.Tests.XamarinIOS.Unified.csproj @@ -123,51 +123,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs - + diff --git a/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj b/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj index 45c4445d5..fdea96c5d 100644 --- a/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj +++ b/tests/SQLite.Net.Tests.XamarinIOS/SQLite.Net.Tests.XamarinIOS.csproj @@ -73,51 +73,7 @@ iPhone Distribution - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OrderByTests.cs - + From 1a3d092e79e6ce5a543566569975e534c4ea6a2a Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 2 Sep 2016 16:34:45 +0200 Subject: [PATCH 3/5] - Addition AppVeyor fixes. Everything compiles fine on my machine, unsure how to check for errors before pushing changes. Hope I haven't missed anything. --- tests/OrderByTests.cs | 2 +- tests/SelectTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/OrderByTests.cs b/tests/OrderByTests.cs index afb7172f2..e8beb5339 100644 --- a/tests/OrderByTests.cs +++ b/tests/OrderByTests.cs @@ -30,7 +30,7 @@ public override string ToString() public override bool Equals(Object obj) { - return Id == (obj as TestObj)?.Id; + return obj is TestObj && Id == ((TestObj)obj).Id; } protected bool Equals(TestObj other) diff --git a/tests/SelectTests.cs b/tests/SelectTests.cs index 86f2c3619..84c43ca23 100644 --- a/tests/SelectTests.cs +++ b/tests/SelectTests.cs @@ -62,7 +62,7 @@ public void SelectWorks() Assert.That( db.Table() - .SelectColumns("`{0}` * 2 as `Order`", nameof(TestObj.Order)) + .SelectColumns("`{0}` * 2 as `Order`", "Order") .Select(obj => obj.Order).First(), Is.EqualTo(10)); } From d2983c1b62e2a3b4a9f6ef243ef1649f1b0cab8d Mon Sep 17 00:00:00 2001 From: Alexis Date: Fri, 2 Sep 2016 17:04:07 +0200 Subject: [PATCH 4/5] - Removed backquotes ` which are non-standard SQL - Renamed MapTo type parameter to a more meaningful denomination --- src/SQLite.Net/TableQuery.cs | 10 +++++----- tests/SelectTests.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SQLite.Net/TableQuery.cs b/src/SQLite.Net/TableQuery.cs index 9308d1774..6fa2b067a 100644 --- a/src/SQLite.Net/TableQuery.cs +++ b/src/SQLite.Net/TableQuery.cs @@ -116,16 +116,16 @@ IEnumerator IEnumerable.GetEnumerator() } [PublicAPI] - public IEnumerable MapTo( + public IEnumerable MapTo( bool selectFromAvailableProperties = true) { if (selectFromAvailableProperties) SelectColumns(_sqlitePlatform.ReflectionService - .GetPublicInstanceProperties(typeof(U)) + .GetPublicInstanceProperties(typeof(TMapped)) .Select(prop => prop.Name) .ToArray()); - return GetEnumerable(); + return GetEnumerable(); } [PublicAPI] @@ -372,9 +372,9 @@ public TableQuery SelectColumns(params string[] propertiesName) string selectSqlStatement = ""; for (; i < propertiesName.Length - 1; i++) - selectSqlStatement += "`{" + i + "}`, "; + selectSqlStatement += "\"{" + i + "}\", "; - return SelectColumns(selectSqlStatement + "`{" + i + "}`", propertiesName); + return SelectColumns(selectSqlStatement + "\"{" + i + "}\"", propertiesName); } public TableQuery SelectColumns(string selectSqlStatement, diff --git a/tests/SelectTests.cs b/tests/SelectTests.cs index 84c43ca23..80e059b88 100644 --- a/tests/SelectTests.cs +++ b/tests/SelectTests.cs @@ -62,7 +62,7 @@ public void SelectWorks() Assert.That( db.Table() - .SelectColumns("`{0}` * 2 as `Order`", "Order") + .SelectColumns("\"{0}\" * 2 as \"Order\"", "Order") .Select(obj => obj.Order).First(), Is.EqualTo(10)); } From 8aceac153cecca2f4a3e3bc47258cda69f8cad1a Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 20 Sep 2016 10:42:17 +0200 Subject: [PATCH 5/5] * Added OrderBy (string) --- src/SQLite.Net/TableQuery.cs | 40 ++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/SQLite.Net/TableQuery.cs b/src/SQLite.Net/TableQuery.cs index 6fa2b067a..78d341576 100644 --- a/src/SQLite.Net/TableQuery.cs +++ b/src/SQLite.Net/TableQuery.cs @@ -252,24 +252,49 @@ public TableQuery OrderBy(Expression> orderExpr) return AddOrderBy(orderExpr, true); } + [PublicAPI] + public TableQuery OrderBy(string propertyName) + { + return AddOrderBy(propertyName, true); + } + [PublicAPI] public TableQuery OrderByDescending(Expression> orderExpr) { return AddOrderBy(orderExpr, false); } + [PublicAPI] + public TableQuery OrderByDescending(string propertyName) + { + return AddOrderBy(propertyName, false); + } + [PublicAPI] public TableQuery ThenBy(Expression> orderExpr) { return AddOrderBy(orderExpr, true); } + [PublicAPI] + public TableQuery ThenBy(string propertyName) + { + return AddOrderBy(propertyName, true); + } + [PublicAPI] public TableQuery ThenByDescending(Expression> orderExpr) { return AddOrderBy(orderExpr, false); } + [PublicAPI] + public TableQuery ThenByDescending(string propertyName) + { + return AddOrderBy(propertyName, false); + } + + [PublicAPI] public TableQuery OrderByRand() { if (_orderBys != null) @@ -282,7 +307,8 @@ public TableQuery OrderByRand() return q; } - private TableQuery AddOrderBy([NotNull] Expression> orderExpr, bool asc) + [PublicAPI] + public TableQuery AddOrderBy([NotNull]Expression> orderExpr, bool asc) { if (orderExpr == null) { @@ -314,16 +340,26 @@ private TableQuery AddOrderBy([NotNull] Expression> o { throw new NotSupportedException("Order By does not support: " + orderExpr); } + + return AddOrderBy(mem.Member.Name, asc); + } + + [PublicAPI] + public TableQuery AddOrderBy([NotNull] string propertyName, bool asc) + { var q = (TableQuery)Clone(); + if (q._orderBys == null) { q._orderBys = new List(); } + q._orderBys.Add(new Ordering { - ColumnName = Table.FindColumnWithPropertyName(mem.Member.Name).Name, + ColumnName = Table.FindColumnWithPropertyName(propertyName).Name, Ascending = asc }); + return q; }