Skip to content

Commit

Permalink
StartsWith, EndsWith, and Contains generated SQL behaves like the Sys…
Browse files Browse the repository at this point in the history
…tem.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
  • Loading branch information
Andrew Tavera committed Jul 11, 2017
1 parent 967e8f6 commit 665007a
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 16 deletions.
48 changes: 42 additions & 6 deletions src/SQLite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3001,17 +3001,53 @@ private CompileResult CompileExpr (Expression expr, List<object> queryArgs)
}
else if (call.Method.Name == "Contains" && args.Length == 1) {
if (call.Object != null && call.Object.Type == typeof(string)) {
sqlCall = "(" + obj.CommandText + " like ('%' || " + args [0].CommandText + " || '%'))";
sqlCall = "( instr(" + obj.CommandText + "," + args [0].CommandText + ") >0 )";
}
else {
sqlCall = "(" + args [0].CommandText + " in " + obj.CommandText + ")";
}
}
else if (call.Method.Name == "StartsWith" && args.Length == 1) {
sqlCall = "(" + obj.CommandText + " like (" + args [0].CommandText + " || '%'))";
}
else if (call.Method.Name == "EndsWith" && args.Length == 1) {
sqlCall = "(" + obj.CommandText + " like ('%' || " + args [0].CommandText + "))";
else if (call.Method.Name == "StartsWith" && args.Length >= 1)
{
var startsWithCmpOp = StringComparison.CurrentCulture;
if (args.Length == 2)
{
startsWithCmpOp = (StringComparison) args[1].Value;
}
switch (startsWithCmpOp)
{
case StringComparison.Ordinal:
case StringComparison.CurrentCulture:
case StringComparison.InvariantCulture:
sqlCall = "( substr(" + obj.CommandText + ", 1, " + args[0].Value.ToString().Length + ") = " + args[0].CommandText + ")";
break;
case StringComparison.OrdinalIgnoreCase:
case StringComparison.CurrentCultureIgnoreCase:
case StringComparison.InvariantCultureIgnoreCase:
sqlCall = "(" + obj.CommandText + " like (" + args[0].CommandText + " || '%'))";
break;
}

}
else if (call.Method.Name == "EndsWith" && args.Length >= 1) {
var endsWithCmpOp = StringComparison.CurrentCulture;
if (args.Length == 2)
{
endsWithCmpOp = (StringComparison)args[1].Value;
}
switch (endsWithCmpOp)
{
case StringComparison.Ordinal:
case StringComparison.CurrentCulture:
case StringComparison.InvariantCulture:
sqlCall = "( substr(" + obj.CommandText + ", length(" + obj.CommandText + ") - "+args[0].Value.ToString().Length+ "+1, " + args[0].Value.ToString().Length + ") = " + args[0].CommandText + ")";
break;
case StringComparison.OrdinalIgnoreCase:
case StringComparison.CurrentCultureIgnoreCase:
case StringComparison.InvariantCultureIgnoreCase:
sqlCall = "(" + obj.CommandText + " like ('%' || " + args[0].CommandText + "))";
break;
}
}
else if (call.Method.Name == "Equals" && args.Length == 1) {
sqlCall = "(" + obj.CommandText + " = (" + args[0].CommandText + "))";
Expand Down
40 changes: 30 additions & 10 deletions tests/StringQueryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,49 @@ public void StartsWith ()
{
var fs = db.Table<Product> ().Where (x => x.Name.StartsWith ("F")).ToList ();
Assert.AreEqual (2, fs.Count);

var bs = db.Table<Product> ().Where (x => x.Name.StartsWith ("B")).ToList ();

var lfs = db.Table<Product>().Where(x => x.Name.StartsWith("f")).ToList();
Assert.AreEqual(0, lfs.Count);


var lfs2 = db.Table<Product>().Where(x => x.Name.StartsWith("f",StringComparison.OrdinalIgnoreCase)).ToList();
Assert.AreEqual(2, lfs2.Count);


var bs = db.Table<Product> ().Where (x => x.Name.StartsWith ("B")).ToList ();
Assert.AreEqual (1, bs.Count);
}

[Test]
public void EndsWith ()
{
var fs = db.Table<Product> ().Where (x => x.Name.EndsWith ("ar")).ToList ();
Assert.AreEqual (2, fs.Count);

var bs = db.Table<Product> ().Where (x => x.Name.EndsWith ("o")).ToList ();
Assert.AreEqual (2, fs.Count);

var lfs = db.Table<Product>().Where(x => x.Name.EndsWith("Ar")).ToList();
Assert.AreEqual(0, lfs.Count);

var bs = db.Table<Product> ().Where (x => x.Name.EndsWith ("o")).ToList ();
Assert.AreEqual (1, bs.Count);
}

[Test]
public void Contains ()
{
var fs = db.Table<Product> ().Where (x => x.Name.Contains ("o")).ToList ();
Assert.AreEqual (2, fs.Count);

var bs = db.Table<Product> ().Where (x => x.Name.Contains ("a")).ToList ();
var fs = db.Table<Product>().Where(x => x.Name.Contains("o")).ToList();
Assert.AreEqual(2, fs.Count);

var lfs = db.Table<Product> ().Where (x => x.Name.Contains ("O")).ToList ();
Assert.AreEqual (0, lfs.Count);

var lfsu = db.Table<Product>().Where(x => x.Name.ToUpper().Contains("O")).ToList();
Assert.AreEqual(2, lfsu.Count);

var bs = db.Table<Product> ().Where (x => x.Name.Contains ("a")).ToList ();
Assert.AreEqual (2, bs.Count);
}

var zs = db.Table<Product>().Where(x => x.Name.Contains("z")).ToList();
Assert.AreEqual(0, zs.Count);
}
}
}

0 comments on commit 665007a

Please sign in to comment.