Skip to content

Commit 665007a

Browse files
author
Andrew Tavera
committed
StartsWith, EndsWith, and Contains generated SQL behaves like the System.String methods used to construct the query:
Contains is case sensitive, using instr() instead of like(). ToUpper() or ToLower can be used to compare without case sensitivity. StartsWith and EndsWith is case sensitive unless a case insensitive StringComparison argument is passed using substr() = ? or the original like() depending upon case sensitivity
1 parent 967e8f6 commit 665007a

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

src/SQLite.cs

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3001,17 +3001,53 @@ private CompileResult CompileExpr (Expression expr, List<object> queryArgs)
30013001
}
30023002
else if (call.Method.Name == "Contains" && args.Length == 1) {
30033003
if (call.Object != null && call.Object.Type == typeof(string)) {
3004-
sqlCall = "(" + obj.CommandText + " like ('%' || " + args [0].CommandText + " || '%'))";
3004+
sqlCall = "( instr(" + obj.CommandText + "," + args [0].CommandText + ") >0 )";
30053005
}
30063006
else {
30073007
sqlCall = "(" + args [0].CommandText + " in " + obj.CommandText + ")";
30083008
}
30093009
}
3010-
else if (call.Method.Name == "StartsWith" && args.Length == 1) {
3011-
sqlCall = "(" + obj.CommandText + " like (" + args [0].CommandText + " || '%'))";
3012-
}
3013-
else if (call.Method.Name == "EndsWith" && args.Length == 1) {
3014-
sqlCall = "(" + obj.CommandText + " like ('%' || " + args [0].CommandText + "))";
3010+
else if (call.Method.Name == "StartsWith" && args.Length >= 1)
3011+
{
3012+
var startsWithCmpOp = StringComparison.CurrentCulture;
3013+
if (args.Length == 2)
3014+
{
3015+
startsWithCmpOp = (StringComparison) args[1].Value;
3016+
}
3017+
switch (startsWithCmpOp)
3018+
{
3019+
case StringComparison.Ordinal:
3020+
case StringComparison.CurrentCulture:
3021+
case StringComparison.InvariantCulture:
3022+
sqlCall = "( substr(" + obj.CommandText + ", 1, " + args[0].Value.ToString().Length + ") = " + args[0].CommandText + ")";
3023+
break;
3024+
case StringComparison.OrdinalIgnoreCase:
3025+
case StringComparison.CurrentCultureIgnoreCase:
3026+
case StringComparison.InvariantCultureIgnoreCase:
3027+
sqlCall = "(" + obj.CommandText + " like (" + args[0].CommandText + " || '%'))";
3028+
break;
3029+
}
3030+
3031+
}
3032+
else if (call.Method.Name == "EndsWith" && args.Length >= 1) {
3033+
var endsWithCmpOp = StringComparison.CurrentCulture;
3034+
if (args.Length == 2)
3035+
{
3036+
endsWithCmpOp = (StringComparison)args[1].Value;
3037+
}
3038+
switch (endsWithCmpOp)
3039+
{
3040+
case StringComparison.Ordinal:
3041+
case StringComparison.CurrentCulture:
3042+
case StringComparison.InvariantCulture:
3043+
sqlCall = "( substr(" + obj.CommandText + ", length(" + obj.CommandText + ") - "+args[0].Value.ToString().Length+ "+1, " + args[0].Value.ToString().Length + ") = " + args[0].CommandText + ")";
3044+
break;
3045+
case StringComparison.OrdinalIgnoreCase:
3046+
case StringComparison.CurrentCultureIgnoreCase:
3047+
case StringComparison.InvariantCultureIgnoreCase:
3048+
sqlCall = "(" + obj.CommandText + " like ('%' || " + args[0].CommandText + "))";
3049+
break;
3050+
}
30153051
}
30163052
else if (call.Method.Name == "Equals" && args.Length == 1) {
30173053
sqlCall = "(" + obj.CommandText + " = (" + args[0].CommandText + "))";

tests/StringQueryTest.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,29 +62,49 @@ public void StartsWith ()
6262
{
6363
var fs = db.Table<Product> ().Where (x => x.Name.StartsWith ("F")).ToList ();
6464
Assert.AreEqual (2, fs.Count);
65-
66-
var bs = db.Table<Product> ().Where (x => x.Name.StartsWith ("B")).ToList ();
65+
66+
var lfs = db.Table<Product>().Where(x => x.Name.StartsWith("f")).ToList();
67+
Assert.AreEqual(0, lfs.Count);
68+
69+
70+
var lfs2 = db.Table<Product>().Where(x => x.Name.StartsWith("f",StringComparison.OrdinalIgnoreCase)).ToList();
71+
Assert.AreEqual(2, lfs2.Count);
72+
73+
74+
var bs = db.Table<Product> ().Where (x => x.Name.StartsWith ("B")).ToList ();
6775
Assert.AreEqual (1, bs.Count);
6876
}
6977

7078
[Test]
7179
public void EndsWith ()
7280
{
7381
var fs = db.Table<Product> ().Where (x => x.Name.EndsWith ("ar")).ToList ();
74-
Assert.AreEqual (2, fs.Count);
75-
76-
var bs = db.Table<Product> ().Where (x => x.Name.EndsWith ("o")).ToList ();
82+
Assert.AreEqual (2, fs.Count);
83+
84+
var lfs = db.Table<Product>().Where(x => x.Name.EndsWith("Ar")).ToList();
85+
Assert.AreEqual(0, lfs.Count);
86+
87+
var bs = db.Table<Product> ().Where (x => x.Name.EndsWith ("o")).ToList ();
7788
Assert.AreEqual (1, bs.Count);
7889
}
7990

8091
[Test]
8192
public void Contains ()
8293
{
83-
var fs = db.Table<Product> ().Where (x => x.Name.Contains ("o")).ToList ();
84-
Assert.AreEqual (2, fs.Count);
85-
86-
var bs = db.Table<Product> ().Where (x => x.Name.Contains ("a")).ToList ();
94+
var fs = db.Table<Product>().Where(x => x.Name.Contains("o")).ToList();
95+
Assert.AreEqual(2, fs.Count);
96+
97+
var lfs = db.Table<Product> ().Where (x => x.Name.Contains ("O")).ToList ();
98+
Assert.AreEqual (0, lfs.Count);
99+
100+
var lfsu = db.Table<Product>().Where(x => x.Name.ToUpper().Contains("O")).ToList();
101+
Assert.AreEqual(2, lfsu.Count);
102+
103+
var bs = db.Table<Product> ().Where (x => x.Name.Contains ("a")).ToList ();
87104
Assert.AreEqual (2, bs.Count);
88-
}
105+
106+
var zs = db.Table<Product>().Where(x => x.Name.Contains("z")).ToList();
107+
Assert.AreEqual(0, zs.Count);
108+
}
89109
}
90110
}

0 commit comments

Comments
 (0)