Skip to content
Open
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
12 changes: 12 additions & 0 deletions QueryBuilder.Tests/SelectTests.cs
Original file line number Diff line number Diff line change
@@ -930,6 +930,18 @@ public void SelectWithExists_OmitSelectIsFalse()
var sqlServer = compiler.Compile(q).ToString();
Assert.Equal("SELECT * FROM [Posts] WHERE EXISTS (SELECT [Id] FROM [Comments] WHERE [Comments].[PostId] = [Posts].[Id])", sqlServer.ToString());
}
[Fact]
public void SelectWithDatePart()
{
var q = new Query().From("users as u").SelectDatePart("day","date","date_day");
var c = Compile(q);

Assert.Equal("SELECT DAY(`date`) AS `date_day` FROM `users` AS `u`", c[EngineCodes.MySql]);
Assert.Equal("SELECT strftime('%d', \"date\") AS \"date_day\" FROM \"users\" AS \"u\"", c[EngineCodes.Sqlite]);
Assert.Equal("SELECT DAY(`date`) AS `date_day` FROM `users` AS `u`", c[EngineCodes.MySql]);
Assert.Equal("SELECT EXTRACT(DAY FROM \"DATE\") AS \"DATE_DAY\" FROM \"USERS\" AS \"U\"", c[EngineCodes.Firebird]);
Assert.Equal("SELECT DATEPART(DAY, [date]) AS [date_day] FROM [users] AS [u]", c[EngineCodes.SqlServer]);
Assert.Equal("SELECT EXTRACT(DAY FROM \"date\") \"date_day\" FROM \"users\" \"u\"", c[EngineCodes.Oracle]);
}
}
}
15 changes: 15 additions & 0 deletions QueryBuilder.Tests/SqlServer/SqlServerTests.cs
Original file line number Diff line number Diff line change
@@ -58,5 +58,20 @@ public void OffsetSqlServer_Should_Be_Incremented_By_One(int offset)
"SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [row_num] FROM [users]) AS [results_wrapper] WHERE [row_num] >= " +
(offset + 1), c.ToString());
}

[Fact]
public void SqlServerOrderByTimePart()
{
var query = new Query("table").OrderByDatePart("year","field");
var result = compiler.Compile(query);
Assert.Equal("SELECT * FROM [table] ORDER BY DATEPART(YEAR, [field])", result.Sql);
}
[Fact]
public void SqlServerGroupByTimePart()
{
var query = new Query("table").GroupByDatePart("year", "field").SelectDatePart("year","field","meow");
var result = compiler.Compile(query);
Assert.Equal("SELECT DATEPART(YEAR, [field]) AS [meow] FROM [table] GROUP BY DATEPART(YEAR, [field])", result.Sql);
}
}
}
21 changes: 21 additions & 0 deletions QueryBuilder/Clauses/ColumnClause.cs
Original file line number Diff line number Diff line change
@@ -29,6 +29,27 @@ public override AbstractClause Clone()
};
}
}
/// <summary>
/// Represents date column clause calculated using query.
/// </summary>
public class DateQueryColumn : Column
{
public string Column { get; set; }

public string Part { get; set; }

public override AbstractClause Clone()
{
return new DateQueryColumn
{
Engine = Engine,
Name=Name,
Column = Column,
Component = Component,
Part = Part,
};
}
}

/// <summary>
/// Represents column clause calculated using query.
16 changes: 16 additions & 0 deletions QueryBuilder/Clauses/OrderClause.cs
Original file line number Diff line number Diff line change
@@ -4,7 +4,23 @@ public abstract class AbstractOrderBy : AbstractClause
{

}
public class DateOrderBy : OrderBy
{
public string Part { get; set; }

/// <inheritdoc />
public override AbstractClause Clone()
{
return new DateOrderBy
{
Engine = Engine,
Component = Component,
Column = Column,
Part= Part,
Ascending = Ascending
};
}
}
public class OrderBy : AbstractOrderBy
{
public string Column { get; set; }
30 changes: 30 additions & 0 deletions QueryBuilder/Compilers/Compiler.cs
Original file line number Diff line number Diff line change
@@ -227,6 +227,16 @@ protected virtual SqlResult CompileSelectQuery(Query query)
return ctx;
}


protected virtual string CompileBasicDateSelect(SqlResult ctx, DateQueryColumn x)
{
var column = Wrap(x.Column);

var sql = $"{x.Part.ToUpperInvariant()}({column})";

return sql;
}

protected virtual SqlResult CompileAdHocQuery(AdHocTableFromClause adHoc)
{
var ctx = new SqlResult();
@@ -531,7 +541,19 @@ public virtual string CompileColumn(SqlResult ctx, AbstractColumn column)

return "(" + subCtx.RawSql + $"){alias}";
}
if (column is DateQueryColumn dateQueryColumn)
{
var alias = "";

if (!string.IsNullOrWhiteSpace(dateQueryColumn.Name))
{
alias = $" {ColumnAsKeyword}{WrapValue(dateQueryColumn.Name)}";
}

var subCtx = CompileBasicDateSelect(ctx,dateQueryColumn);

return subCtx + $"{alias}";
}
if (column is AggregatedColumn aggregatedColumn)
{
string agg = aggregatedColumn.Aggregate.ToUpperInvariant();
@@ -801,6 +823,14 @@ public virtual string CompileOrders(SqlResult ctx)
ctx.Bindings.AddRange(raw.Bindings);
return WrapIdentifiers(raw.Expression);
}
if (x is DateOrderBy dateOrderBy)
{
var direct = dateOrderBy.Ascending ? "" : " DESC";

var sql = CompileBasicDateSelect(ctx, new DateQueryColumn { Column = dateOrderBy.Column, Part = dateOrderBy.Part });

return sql + direct;
}

var direction = (x as OrderBy).Ascending ? "" : " DESC";

22 changes: 22 additions & 0 deletions QueryBuilder/Compilers/FirebirdCompiler.cs
Original file line number Diff line number Diff line change
@@ -73,6 +73,28 @@ protected override string CompileColumns(SqlResult ctx)
return compiled;
}

protected override string CompileBasicDateSelect(SqlResult ctx, DateQueryColumn x)
{
var column = Wrap(x.Column);

string left;

if (x.Part == "time")
{
left = $"CAST({column} as TIME)";
}
else if (x.Part == "date")
{
left = $"CAST({column} as DATE)";
}
else
{
left = $"EXTRACT({x.Part.ToUpperInvariant()} FROM {column})";
}

return left;
}

protected override string CompileBasicDateCondition(SqlResult ctx, BasicDateCondition condition)
{
var column = Wrap(condition.Column);
27 changes: 27 additions & 0 deletions QueryBuilder/Compilers/OracleCompiler.cs
Original file line number Diff line number Diff line change
@@ -99,7 +99,34 @@ internal void ApplyLegacyLimit(SqlResult ctx)

ctx.RawSql = newSql;
}
protected override string CompileBasicDateSelect(SqlResult ctx, DateQueryColumn x)
{
var column = Wrap(x.Column);

string sql;
switch (x.Part)
{
case "date": // assume YY-MM-DD format
sql = $"TO_CHAR({column}, 'YY-MM-DD')";
break;
case "time":
sql = $"TO_CHAR({column}, 'HH24:MI:SS')";
break;
case "year":
case "month":
case "day":
case "hour":
case "minute":
case "second":
sql = $"EXTRACT({x.Part.ToUpperInvariant()} FROM {column})";
break;
default:
sql = column;
break;
}

return sql;
}
protected override string CompileBasicDateCondition(SqlResult ctx, BasicDateCondition condition)
{

22 changes: 22 additions & 0 deletions QueryBuilder/Compilers/PostgresCompiler.cs
Original file line number Diff line number Diff line change
@@ -66,6 +66,28 @@ protected override string CompileBasicStringCondition(SqlResult ctx, BasicString

}

protected override string CompileBasicDateSelect(SqlResult ctx, DateQueryColumn x)
{

var column = Wrap(x.Column);

string left;

if (x.Part == "time")
{
left = $"{column}::time";
}
else if (x.Part == "date")
{
left = $"{column}::date";
}
else
{
left = $"DATE_PART('{x.Part.ToUpperInvariant()}', {column})";
}

return left;
}

protected override string CompileBasicDateCondition(SqlResult ctx, BasicDateCondition condition)
{
17 changes: 17 additions & 0 deletions QueryBuilder/Compilers/SqlServerCompiler.cs
Original file line number Diff line number Diff line change
@@ -144,7 +144,24 @@ public override string CompileFalse()
{
return "cast(0 as bit)";
}
protected override string CompileBasicDateSelect(SqlResult ctx, DateQueryColumn x)
{
var column = Wrap(x.Column);
var part = x.Part.ToUpperInvariant();

string left;

if (part == "TIME" || part == "DATE")
{
left = $"CAST({column} AS {part.ToUpperInvariant()})";
}
else
{
left = $"DATEPART({part.ToUpperInvariant()}, {column})";
}

return left;
}
protected override string CompileBasicDateCondition(SqlResult ctx, BasicDateCondition condition)
{
var column = Wrap(condition.Column);
22 changes: 22 additions & 0 deletions QueryBuilder/Compilers/SqliteCompiler.cs
Original file line number Diff line number Diff line change
@@ -19,7 +19,29 @@ public override string CompileFalse()
{
return "0";
}
protected override string CompileBasicDateSelect(SqlResult ctx, DateQueryColumn x)
{
var column = Wrap(x.Column);

var formatMap = new Dictionary<string, string> {
{ "date", "%Y-%m-%d" },
{ "time", "%H:%M:%S" },
{ "year", "%Y" },
{ "month", "%m" },
{ "day", "%d" },
{ "hour", "%H" },
{ "minute", "%M" },
};

if (!formatMap.ContainsKey(x.Part))
{
return column;
}

var sql = $"strftime('{formatMap[x.Part]}', {column})";

return sql;
}
public override string CompileLimit(SqlResult ctx)
{
var limit = ctx.Query.GetLimit(EngineCode);
22 changes: 22 additions & 0 deletions QueryBuilder/Query.Select.cs
Original file line number Diff line number Diff line change
@@ -117,5 +117,27 @@ public Query SelectMax(string column, Func<Query, Query> filter = null)
{
return SelectAggregate("max", column, filter);
}

#region date
public Query SelectDatePart(string part, string column,string alias)
{
return AddComponent("select", new DateQueryColumn
{
Name = alias,
Part = part?.ToLowerInvariant(),
Column=column
});
}

public Query SelectDate(string column, string alias)
{
return SelectDatePart("date", column, alias);
}
public Query SelectTime(string column, string alias)
{
return SelectDatePart("time", column, alias);
}
#endregion

}
}
57 changes: 57 additions & 0 deletions QueryBuilder/Query.cs
Original file line number Diff line number Diff line change
@@ -335,7 +335,64 @@ public Query GroupByRaw(string expression, params object[] bindings)

return this;
}
#region date
public Query OrderByDatePart(string part, string column)
{
return AddComponent("order", new DateOrderBy
{
Part = part?.ToLowerInvariant(),
Column = column,
Ascending = true
});
}

public Query OrderByDate(string column)
{
return OrderByDatePart("date", column);
}
public Query OrderByTime(string column)
{
return OrderByDatePart("time", column);
}

public Query OrderByDatePartDesc(string part, string column)
{
return AddComponent("order", new DateOrderBy
{
Part = part?.ToLowerInvariant(),
Column = column,
Ascending = true
});
}

public Query OrderByDateDesc(string column)
{
return OrderByDatePartDesc("date", column);
}
public Query OrderByTimeDesc(string column)
{
return OrderByDatePartDesc("time", column);
}

public Query GroupByDatePart(string part, string column)
{
return AddComponent("group", new DateQueryColumn
{
Part = part?.ToLowerInvariant(),
Column = column
});
}

public Query GroupByDate(string column)
{
return OrderByDatePart("date", column);
}
public Query GroupByTime(string column)
{
return OrderByDatePart("time", column);
}

#endregion
public override Query NewQuery()
{
return new Query();