diff --git a/Program/Demo.db b/Program/Demo.db
new file mode 100644
index 00000000..d2055d82
Binary files /dev/null and b/Program/Demo.db differ
diff --git a/Program/Program.cs b/Program/Program.cs
index c8d79ed3..d840ff1f 100644
--- a/Program/Program.cs
+++ b/Program/Program.cs
@@ -10,6 +10,8 @@
using Npgsql;
using System.Data;
using Dapper;
+using System.Data.SQLite;
+using Sqlkata.Compilers;
namespace Program
{
@@ -36,19 +38,17 @@ static void Main(string[] args)
"Server=tcp:localhost,1433;Initial Catalog=Lite;User ID=sa;Password=P@ssw0rd"
);
- var db = new QueryFactory(connection, new SqlServerCompiler
- {
- UseLegacyPagination = true
- });
+ // SQLiteConnection.CreateFile("Demo.db");
+
+ connection = new SQLiteConnection("Data Source=Demo.db");
+
+ var db = new QueryFactory(connection, new SqliteCompiler());
+
+ // db.Statement("create table accounts(id integer primary key,name text,currency_id text);");
db.Logger = q => Console.WriteLine(q.ToString());
- var accounts = db.Query("Accounts")
- .ForPage(2, 10)
- .WhereRaw("[CurrencyId] in (?)", new object[] { 11 })
- .WhereRaw("[CurrencyId] in (?)", new[] { 1, 2, 3 })
- .WhereRaw("[CurrencyId] in (?)", new[] { "100", "200" })
- .Get();
+ var accounts = db.Query("Accounts").OrderByDesc("Id").Offset(10).Get();
Console.WriteLine(JsonConvert.SerializeObject(accounts));
diff --git a/Program/Program.csproj b/Program/Program.csproj
index 48aa1e8f..357d6785 100644
--- a/Program/Program.csproj
+++ b/Program/Program.csproj
@@ -9,6 +9,7 @@
+
diff --git a/QueryBuilder.Tests/SqliteLimitTest.cs b/QueryBuilder.Tests/SqliteLimitTest.cs
new file mode 100644
index 00000000..ded0fff5
--- /dev/null
+++ b/QueryBuilder.Tests/SqliteLimitTest.cs
@@ -0,0 +1,53 @@
+using Sqlkata.Compilers;
+using SqlKata;
+using Xunit;
+
+namespace SqlKata.Tests
+{
+ public class SqliteLimitTest
+ {
+ private SqliteCompiler compiler = new SqliteCompiler();
+
+ [Fact]
+ public void WithNoLimitNorOffset()
+ {
+ var query = new Query("Table");
+ var ctx = new SqlResult { Query = query };
+
+ Assert.Null(compiler.CompileLimit(ctx));
+ }
+
+ [Fact]
+ public void WithNoOffset()
+ {
+ var query = new Query("Table").Limit(10);
+ var ctx = new SqlResult { Query = query };
+
+ Assert.Equal("LIMIT ?", compiler.CompileLimit(ctx));
+ Assert.Equal(10, ctx.Bindings[0]);
+ }
+
+ [Fact]
+ public void WithNoLimit()
+ {
+ var query = new Query("Table").Offset(20);
+ var ctx = new SqlResult { Query = query };
+
+ Assert.Equal("LIMIT -1 OFFSET ?", compiler.CompileLimit(ctx));
+ Assert.Equal(20, ctx.Bindings[0]);
+ Assert.Single(ctx.Bindings);
+ }
+
+ [Fact]
+ public void WithLimitAndOffset()
+ {
+ var query = new Query("Table").Limit(5).Offset(20);
+ var ctx = new SqlResult { Query = query };
+
+ Assert.Equal("LIMIT ? OFFSET ?", compiler.CompileLimit(ctx));
+ Assert.Equal(5, ctx.Bindings[0]);
+ Assert.Equal(20, ctx.Bindings[1]);
+ Assert.Equal(2, ctx.Bindings.Count);
+ }
+ }
+}
\ No newline at end of file
diff --git a/QueryBuilder/Compilers/Compiler.cs b/QueryBuilder/Compilers/Compiler.cs
index 1f1502f4..41dccd32 100644
--- a/QueryBuilder/Compilers/Compiler.cs
+++ b/QueryBuilder/Compilers/Compiler.cs
@@ -8,8 +8,13 @@ namespace SqlKata.Compilers
public abstract partial class Compiler
{
private readonly ConditionsCompilerProvider _compileConditionMethodsProvider;
- protected string parameterPlaceholder = "?";
- protected string parameterPlaceholderPrefix = "@p";
+ protected virtual string parameterPlaceholder { get; set; } = "?";
+ protected virtual string parameterPlaceholderPrefix { get; set; } = "@p";
+ protected virtual string OpeningIdentifier { get; set; } = "\"";
+ protected virtual string ClosingIdentifier { get; set; } = "\"";
+ protected virtual string ColumnAsKeyword { get; set; } = "AS ";
+ protected virtual string TableAsKeyword { get; set; } = "AS ";
+ protected virtual string LastId { get; set; } = "";
protected Compiler()
{
@@ -17,11 +22,7 @@ protected Compiler()
}
public abstract string EngineCode { get; }
- protected string OpeningIdentifier = "\"";
- protected string ClosingIdentifier = "\"";
- protected string ColumnAsKeyword = "AS ";
- protected string TableAsKeyword = "AS ";
- protected string LastId = "";
+
///
/// A list of white-listed operators
@@ -588,7 +589,7 @@ public virtual string CompileOrders(SqlResult ctx)
return "ORDER BY " + string.Join(", ", columns);
}
- public string CompileHaving(SqlResult ctx)
+ public virtual string CompileHaving(SqlResult ctx)
{
if (!ctx.Query.HasComponent("having", EngineCode))
{
diff --git a/QueryBuilder/Compilers/SqlServerCompiler.cs b/QueryBuilder/Compilers/SqlServerCompiler.cs
index 51e08e30..be24ce19 100644
--- a/QueryBuilder/Compilers/SqlServerCompiler.cs
+++ b/QueryBuilder/Compilers/SqlServerCompiler.cs
@@ -37,7 +37,9 @@ protected override SqlResult CompileSelectQuery(Query query)
{
query.Select("*");
}
+
var order = CompileOrders(ctx) ?? "ORDER BY (SELECT 0)";
+
query.SelectRaw($"ROW_NUMBER() OVER ({order}) AS [row_num]", ctx.Bindings.ToArray());
query.ClearComponent("order");
diff --git a/QueryBuilder/Compilers/SqliteCompiler.cs b/QueryBuilder/Compilers/SqliteCompiler.cs
new file mode 100644
index 00000000..a878b3c7
--- /dev/null
+++ b/QueryBuilder/Compilers/SqliteCompiler.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using SqlKata;
+using SqlKata.Compilers;
+
+namespace Sqlkata.Compilers
+{
+ public class SqliteCompiler : Compiler
+ {
+ public override string EngineCode => "sqlite";
+ protected override string parameterPlaceholder { get; set; } = "?";
+ protected override string parameterPlaceholderPrefix { get; set; } = "@p";
+ protected override string OpeningIdentifier { get; set; } = "\"";
+ protected override string ClosingIdentifier { get; set; } = "\"";
+ protected override string LastId { get; set; } = "last_insert_rowid()";
+
+ public override string CompileTrue()
+ {
+ return "1";
+ }
+
+ public override string CompileFalse()
+ {
+ return "0";
+ }
+
+ public override string CompileLimit(SqlResult ctx)
+ {
+ var limit = ctx.Query.GetLimit(EngineCode);
+ var offset = ctx.Query.GetOffset(EngineCode);
+
+ if (limit == 0 && offset > 0)
+ {
+ ctx.Bindings.Add(offset);
+ return "LIMIT -1 OFFSET ?";
+ }
+
+ return base.CompileLimit(ctx);
+ }
+
+ protected override string CompileBasicDateCondition(SqlResult ctx, BasicDateCondition condition)
+ {
+ var column = Wrap(condition.Column);
+ var value = Parameter(ctx, condition.Value);
+
+ var formatMap = new Dictionary {
+ {"date", "%Y-%m-%d"},
+ {"time", "%H:%M:%S"},
+ {"year", "%Y"},
+ {"month", "%m"},
+ {"day", "%d"},
+ {"hour", "%H"},
+ {"minute", "%M"},
+ };
+
+ if (!formatMap.ContainsKey(condition.Part))
+ {
+ return $"{column} {condition.Operator} {value}";
+ }
+
+ var sql = $"strftime('{formatMap[condition.Part]}', {column}) {condition.Operator} cast({value} as text)";
+
+ if (condition.IsNot)
+ {
+ return $"NOT ({sql})";
+ }
+
+ return sql;
+ }
+
+ }
+ public static class SqliteCompilerExtensions
+ {
+ public static string ENGINE_CODE = "sqlite";
+ public static Query ForSqlite(this Query src, Func fn)
+ {
+ return src.For(SqliteCompilerExtensions.ENGINE_CODE, fn);
+ }
+ }
+}
\ No newline at end of file