Skip to content

Support SelectDatePart, GroupByDatePart, OrderByDatePart #632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Up @@ -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
Expand Up @@ -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.
Expand Down
16 changes: 16 additions & 0 deletions QueryBuilder/Clauses/OrderClause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
30 changes: 30 additions & 0 deletions QueryBuilder/Compilers/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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";

Expand Down
22 changes: 22 additions & 0 deletions QueryBuilder/Compilers/FirebirdCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 27 additions & 0 deletions QueryBuilder/Compilers/OracleCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{

Expand Down
22 changes: 22 additions & 0 deletions QueryBuilder/Compilers/PostgresCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
17 changes: 17 additions & 0 deletions QueryBuilder/Compilers/SqlServerCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 22 additions & 0 deletions QueryBuilder/Compilers/SqliteCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 22 additions & 0 deletions QueryBuilder/Query.Select.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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();
Expand Down