From e772e299a0ff00707bfb4fd121ce4f22e2ec3c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Geelen?= Date: Thu, 3 Jun 2021 12:06:47 +0200 Subject: [PATCH 1/4] Make aggregate check input columns. --- QueryBuilder.Tests/AggregateTests.cs | 7 +++++++ QueryBuilder/Query.Aggregate.cs | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/QueryBuilder.Tests/AggregateTests.cs b/QueryBuilder.Tests/AggregateTests.cs index 68a69842..76b228fd 100644 --- a/QueryBuilder.Tests/AggregateTests.cs +++ b/QueryBuilder.Tests/AggregateTests.cs @@ -1,11 +1,18 @@ using SqlKata.Compilers; using SqlKata.Tests.Infrastructure; +using System; using Xunit; namespace SqlKata.Tests { public class AggregateTests : TestSupport { + [Fact] + public void AsAggregateEmpty() + { + Assert.Throws(() => new Query("A").AsAggregate("aggregate", new string[] { })); + } + [Fact] public void Count() { diff --git a/QueryBuilder/Query.Aggregate.cs b/QueryBuilder/Query.Aggregate.cs index d4fc5057..0cdf1192 100644 --- a/QueryBuilder/Query.Aggregate.cs +++ b/QueryBuilder/Query.Aggregate.cs @@ -7,6 +7,10 @@ public partial class Query { public Query AsAggregate(string type, string[] columns = null) { + if (columns.Count() == 0) + { + throw new System.ArgumentException("Cannot aggregate without columns"); + } Method = "aggregate"; From 417f86e29d93bf0500e0656dd2804011a0f555c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Geelen?= Date: Mon, 10 May 2021 10:13:17 +0200 Subject: [PATCH 2/4] Implement column-as keyword for 'select' with SelectAs(). --- QueryBuilder.Tests/SelectTests.cs | 54 ++++++++++++++++++++++++++++ QueryBuilder/Clauses/ColumnClause.cs | 6 ++++ QueryBuilder/Compilers/Compiler.cs | 6 ++++ QueryBuilder/Query.Select.cs | 31 +++++++++++----- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/QueryBuilder.Tests/SelectTests.cs b/QueryBuilder.Tests/SelectTests.cs index 8341bf1f..cd6270be 100644 --- a/QueryBuilder.Tests/SelectTests.cs +++ b/QueryBuilder.Tests/SelectTests.cs @@ -35,6 +35,45 @@ public void BasicSelectEnumerable() Assert.Equal("SELECT \"id\", \"name\" FROM \"users\"", c[EngineCodes.Oracle]); } + [Fact] + public void SelectAsOneColumn() + { + var query = new Query().SelectAs("Row", "Alias").From("Table"); + + var c = Compile(query); + Assert.Equal("SELECT [Row] AS [Alias] FROM [Table]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT `Row` AS `Alias` FROM `Table`", c[EngineCodes.MySql]); + Assert.Equal("SELECT \"Row\" AS \"Alias\" FROM \"Table\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT \"ROW\" AS \"ALIAS\" FROM \"TABLE\"", c[EngineCodes.Firebird]); + Assert.Equal("SELECT \"Row\" \"Alias\" FROM \"Table\"", c[EngineCodes.Oracle]); + } + + [Fact] + public void SelectAsSingletonList() + { + var query = new Query().SelectAs(("Row", "Alias")).From("Table"); + + var c = Compile(query); + Assert.Equal("SELECT [Row] AS [Alias] FROM [Table]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT `Row` AS `Alias` FROM `Table`", c[EngineCodes.MySql]); + Assert.Equal("SELECT \"Row\" AS \"Alias\" FROM \"Table\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT \"ROW\" AS \"ALIAS\" FROM \"TABLE\"", c[EngineCodes.Firebird]); + Assert.Equal("SELECT \"Row\" \"Alias\" FROM \"Table\"", c[EngineCodes.Oracle]); + } + + [Fact] + public void SelectAsMultipleColumns() + { + var query = new Query().SelectAs(("Row1", "Alias1"), ("Row2", "Alias2")).From("Table"); + + var c = Compile(query); + Assert.Equal("SELECT [Row1] AS [Alias1], [Row2] AS [Alias2] FROM [Table]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT `Row1` AS `Alias1`, `Row2` AS `Alias2` FROM `Table`", c[EngineCodes.MySql]); + Assert.Equal("SELECT \"Row1\" AS \"Alias1\", \"Row2\" AS \"Alias2\" FROM \"Table\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT \"ROW1\" AS \"ALIAS1\", \"ROW2\" AS \"ALIAS2\" FROM \"TABLE\"", c[EngineCodes.Firebird]); + Assert.Equal("SELECT \"Row1\" \"Alias1\", \"Row2\" \"Alias2\" FROM \"Table\"", c[EngineCodes.Oracle]); + } + [Fact] public void BasicSelectWhereBindingIsEmptyOrNull() { @@ -74,6 +113,21 @@ public void ExpandedSelect() Assert.Equal("SELECT `users`.`id`, `users`.`name`, `users`.`age` FROM `users`", c[EngineCodes.MySql]); } + [Fact] + public void ExpandedSelectAs() + { + var q = new Query().From("users").SelectAs(("users.{id,name, age}", "Alias")); + var c = Compile(q); + + // This result is weird (but valid syntax), and at least it works in + // a somewhat explainable way, as opposed to regular Select() when + // combining the expanded syntax and the 'as' SQLKata keyword support + // which simply silently stops working when the {...} expansion is + // applied. + Assert.Equal("SELECT [users].[id] AS [Alias], [users].[name] AS [Alias], [users].[age] AS [Alias] FROM [users]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT `users`.`id` AS `Alias`, `users`.`name` AS `Alias`, `users`.`age` AS `Alias` FROM `users`", c[EngineCodes.MySql]); + } + [Fact] public void ExpandedSelectWithSchema() { diff --git a/QueryBuilder/Clauses/ColumnClause.cs b/QueryBuilder/Clauses/ColumnClause.cs index 58872d8e..9de7282d 100644 --- a/QueryBuilder/Clauses/ColumnClause.cs +++ b/QueryBuilder/Clauses/ColumnClause.cs @@ -1,7 +1,10 @@ +using System.Diagnostics; + namespace SqlKata { public abstract class AbstractColumn : AbstractClause { + public string Alias { get; set; } } /// @@ -26,6 +29,7 @@ public override AbstractClause Clone() Engine = Engine, Name = Name, Component = Component, + Alias = Alias, }; } } @@ -50,6 +54,7 @@ public override AbstractClause Clone() Engine = Engine, Query = Query.Clone(), Component = Component, + Alias = Alias, }; } } @@ -68,6 +73,7 @@ public class RawColumn : AbstractColumn /// public override AbstractClause Clone() { + Debug.Assert(string.IsNullOrEmpty(Alias), "Raw columns cannot have an alias"); return new RawColumn { Engine = Engine, diff --git a/QueryBuilder/Compilers/Compiler.cs b/QueryBuilder/Compilers/Compiler.cs index 28abe5a6..3f32db4f 100644 --- a/QueryBuilder/Compilers/Compiler.cs +++ b/QueryBuilder/Compilers/Compiler.cs @@ -472,6 +472,12 @@ public virtual string CompileColumn(SqlResult ctx, AbstractColumn column) return "(" + subCtx.RawSql + $"){alias}"; } + if (!string.IsNullOrWhiteSpace(column.Alias)) + { + return $"{Wrap((column as Column).Name)} {ColumnAsKeyword}{Wrap(column.Alias)}"; + + } + return Wrap((column as Column).Name); } diff --git a/QueryBuilder/Query.Select.cs b/QueryBuilder/Query.Select.cs index f753a388..1d9ca7be 100644 --- a/QueryBuilder/Query.Select.cs +++ b/QueryBuilder/Query.Select.cs @@ -6,27 +6,42 @@ namespace SqlKata { public partial class Query { + public Query Select(params string[] columns) => + Select(columns.AsEnumerable()); - public Query Select(params string[] columns) - { - return Select(columns.AsEnumerable()); - } + public Query Select(IEnumerable columns) => + SelectAs( + columns + .Select(x => (x, null as string)) + .ToArray() + ); + + /// + /// Select a column with an alias + /// + /// + public Query SelectAs(string column, string alias) => + SelectAs((column, alias)); - public Query Select(IEnumerable columns) + /// + /// Select columns with an alias + /// + /// + public Query SelectAs(params (string, string)[] columns) { Method = "select"; columns = columns - .Select(x => Helper.ExpandExpression(x)) + .Select(x => Helper.ExpandExpression(x.Item1).Select(y => (y, x.Item2))) .SelectMany(x => x) .ToArray(); - foreach (var column in columns) { AddComponent("select", new Column { - Name = column + Name = column.Item1, + Alias = column.Item2 }); } From a6ae753a27e4ca3c1e3c0942e3ed5e2f6b8d364b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Geelen?= Date: Thu, 3 Jun 2021 11:14:30 +0200 Subject: [PATCH 3/4] Implement column-as keyword for 'count' aggregate with AsCountAs(). --- QueryBuilder.Tests/AggregateTests.cs | 59 +++++++++++++++++++++++-- QueryBuilder/Clauses/AggregateClause.cs | 6 +++ QueryBuilder/Compilers/Compiler.cs | 14 ++++-- QueryBuilder/Query.Aggregate.cs | 15 +++++-- 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/QueryBuilder.Tests/AggregateTests.cs b/QueryBuilder.Tests/AggregateTests.cs index 76b228fd..22c2f1e1 100644 --- a/QueryBuilder.Tests/AggregateTests.cs +++ b/QueryBuilder.Tests/AggregateTests.cs @@ -26,6 +26,49 @@ public void Count() Assert.Equal("SELECT COUNT(*) AS \"COUNT\" FROM \"A\"", c[EngineCodes.Firebird]); } + [Fact] + public void CountAsStarAlias() + { + var query = new Query("A").AsCountAs("*", "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT COUNT(*) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT COUNT(*) AS `Alias` FROM `A`", c[EngineCodes.MySql]); + Assert.Equal("SELECT COUNT(*) AS \"Alias\" FROM \"A\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT COUNT(*) AS \"ALIAS\" FROM \"A\"", c[EngineCodes.Firebird]); + } + + [Fact] + public void CountAsColumnAlias() + { + var query = new Query("A").AsCountAs("Column", "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT COUNT([Column]) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT COUNT(`Column`) AS `Alias` FROM `A`", c[EngineCodes.MySql]); + Assert.Equal("SELECT COUNT(\"Column\") AS \"Alias\" FROM \"A\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT COUNT(\"COLUMN\") AS \"ALIAS\" FROM \"A\"", c[EngineCodes.Firebird]); + } + + [Fact] + public void CountDoesntModifyColumns() + { + { + var columns = new string[] { }; + var query = new Query("A").AsCount(columns); + Compile(query); + Assert.Equal(columns, new string[] { }); + } + { + var columns = new[] { "ColumnA", "ColumnB" }; + var query = new Query("A").AsCount(columns); + Compile(query); + Assert.Equal(columns, new[] { "ColumnA", "ColumnB" }); + } + } + [Fact] public void CountMultipleColumns() { @@ -33,7 +76,17 @@ public void CountMultipleColumns() var c = Compile(query); - Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) AS [countQuery]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) AS [CountQuery]", c[EngineCodes.SqlServer]); + } + + [Fact] + public void CountAsMultipleColumns() + { + var query = new Query("A").AsCountAs(new[] { "ColumnA", "ColumnB" }, "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT COUNT(*) AS [Alias] FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) AS [AliasCountQuery]", c[EngineCodes.SqlServer]); } [Fact] @@ -43,7 +96,7 @@ public void DistinctCount() var c = Compile(query); - Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT * FROM [A]) AS [countQuery]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT * FROM [A]) AS [CountQuery]", c[EngineCodes.SqlServer]); } [Fact] @@ -53,7 +106,7 @@ public void DistinctCountMultipleColumns() var c = Compile(query); - Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT [ColumnA], [ColumnB] FROM [A]) AS [countQuery]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT COUNT(*) AS [count] FROM (SELECT DISTINCT [ColumnA], [ColumnB] FROM [A]) AS [CountQuery]", c[EngineCodes.SqlServer]); } [Fact] diff --git a/QueryBuilder/Clauses/AggregateClause.cs b/QueryBuilder/Clauses/AggregateClause.cs index 2d18d78e..1629db6d 100644 --- a/QueryBuilder/Clauses/AggregateClause.cs +++ b/QueryBuilder/Clauses/AggregateClause.cs @@ -16,6 +16,11 @@ public class AggregateClause : AbstractClause /// public List Columns { get; set; } + /// + /// Gets or sets the alias of the result column. + /// + public string Alias { get; set; } + /// /// Gets or sets the type of aggregate function. /// @@ -32,6 +37,7 @@ public override AbstractClause Clone() Engine = Engine, Type = Type, Columns = new List(Columns), + Alias = Alias, Component = Component, }; } diff --git a/QueryBuilder/Compilers/Compiler.cs b/QueryBuilder/Compilers/Compiler.cs index 3f32db4f..34ca59d5 100644 --- a/QueryBuilder/Compilers/Compiler.cs +++ b/QueryBuilder/Compilers/Compiler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; @@ -69,7 +70,7 @@ private Query TransformAggregateQuery(Query query) { query.ClearComponent("aggregate", EngineCode); query.ClearComponent("select", EngineCode); - query.Select(clause.Columns.ToArray()); + query.SelectAs(clause.Columns.Select(x => (x, null as string)).ToArray()); } else { @@ -82,12 +83,14 @@ private Query TransformAggregateQuery(Query query) var outerClause = new AggregateClause() { Columns = new List { "*" }, - Type = clause.Type + Type = clause.Type, + Alias = clause.Alias, }; return new Query() .AddComponent("aggregate", outerClause) - .From(query, $"{clause.Type}Query"); + // Use alias + capitalized type + 'query' as alias + .From(query, $"{clause.Alias}{clause.Type.First().ToString().ToUpperInvariant()}{clause.Type.Substring(1)}Query"); } protected virtual SqlResult CompileRaw(Query query) @@ -534,9 +537,12 @@ protected virtual string CompileColumns(SqlResult ctx) sql = "DISTINCT " + sql; } - return "SELECT " + aggregate.Type.ToUpperInvariant() + "(" + sql + $") {ColumnAsKeyword}" + WrapValue(aggregate.Type); + return $"SELECT {aggregate.Type.ToUpperInvariant()}({sql}) {ColumnAsKeyword}{WrapValue(aggregate.Alias ?? aggregate.Type)}"; } + // Counts of multiple columns are implemented by a sub-query + // which selects 1 from every non-null record. E.g. + // SELECT COUNT(*) FROM (SELECT 1 FROM [A] WHERE [ColumnA] IS NOT NULL AND [ColumnB] IS NOT NULL) return "SELECT 1"; } diff --git a/QueryBuilder/Query.Aggregate.cs b/QueryBuilder/Query.Aggregate.cs index 0cdf1192..15ea9a31 100644 --- a/QueryBuilder/Query.Aggregate.cs +++ b/QueryBuilder/Query.Aggregate.cs @@ -5,7 +5,7 @@ namespace SqlKata { public partial class Query { - public Query AsAggregate(string type, string[] columns = null) + public Query AsAggregate(string type, IEnumerable columns, string alias = null) { if (columns.Count() == 0) { @@ -18,15 +18,16 @@ public Query AsAggregate(string type, string[] columns = null) .AddComponent("aggregate", new AggregateClause { Type = type, - Columns = columns?.ToList() ?? new List(), + Columns = columns.ToList(), + Alias = alias }); return this; } - public Query AsCount(string[] columns = null) + public Query AsCount(params string[] columns) { - var cols = columns?.ToList() ?? new List { }; + var cols = columns.ToList(); if (!cols.Any()) { @@ -36,6 +37,12 @@ public Query AsCount(string[] columns = null) return AsAggregate("count", cols.ToArray()); } + public Query AsCountAs(string column, string alias) => + AsAggregate("count", new string[] { column }, alias); + + public Query AsCountAs(IEnumerable columns, string alias) => + AsAggregate("count", columns, alias); + public Query AsAvg(string column) { return AsAggregate("avg", new string[] { column }); From 3d14ba81210d17d5da6a9da582f1467cf54cab87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20Geelen?= Date: Fri, 2 Jul 2021 14:24:37 +0200 Subject: [PATCH 4/4] Implement as-keyword support for all aggregates. --- QueryBuilder.Tests/AggregateTests.cs | 92 ++++++++++++++++++++++++++++ QueryBuilder/Query.Aggregate.cs | 68 ++++++++++++++------ 2 files changed, 140 insertions(+), 20 deletions(-) diff --git a/QueryBuilder.Tests/AggregateTests.cs b/QueryBuilder.Tests/AggregateTests.cs index 22c2f1e1..5414547c 100644 --- a/QueryBuilder.Tests/AggregateTests.cs +++ b/QueryBuilder.Tests/AggregateTests.cs @@ -13,6 +13,58 @@ public void AsAggregateEmpty() Assert.Throws(() => new Query("A").AsAggregate("aggregate", new string[] { })); } + [Fact] + public void AsAggregate() + { + var query = new Query("A").AsAggregate("aggregate", new[] { "Column" }); + + var c = Compile(query); + + Assert.Equal("SELECT AGGREGATE([Column]) AS [aggregate] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT AGGREGATE(`Column`) AS `aggregate` FROM `A`", c[EngineCodes.MySql]); + Assert.Equal("SELECT AGGREGATE(\"Column\") AS \"aggregate\" FROM \"A\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT AGGREGATE(\"COLUMN\") AS \"AGGREGATE\" FROM \"A\"", c[EngineCodes.Firebird]); + } + + [Fact] + public void AsAggregateAlias() + { + var query = new Query("A").AsAggregate("aggregate", new[] { "Column" }, "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT AGGREGATE([Column]) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT AGGREGATE(`Column`) AS `Alias` FROM `A`", c[EngineCodes.MySql]); + Assert.Equal("SELECT AGGREGATE(\"Column\") AS \"Alias\" FROM \"A\"", c[EngineCodes.PostgreSql]); + Assert.Equal("SELECT AGGREGATE(\"COLUMN\") AS \"ALIAS\" FROM \"A\"", c[EngineCodes.Firebird]); + } + + [Fact] + public void AsAggregateMultipleColumns() + { + var query = new Query("A").AsAggregate("aggregate", new[] { "Column1", "Column2" }); + + var c = Compile(query); + + Assert.Equal("SELECT AGGREGATE(*) AS [aggregate] FROM (SELECT 1 FROM [A] WHERE [Column1] IS NOT NULL AND [Column2] IS NOT NULL) AS [AggregateQuery]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT AGGREGATE(*) AS `aggregate` FROM (SELECT 1 FROM `A` WHERE `Column1` IS NOT NULL AND `Column2` IS NOT NULL) AS `AggregateQuery`", c[EngineCodes.MySql]); + Assert.Equal("SELECT AGGREGATE(*) AS \"AGGREGATE\" FROM (SELECT 1 FROM \"A\" WHERE \"COLUMN1\" IS NOT NULL AND \"COLUMN2\" IS NOT NULL) AS \"AGGREGATEQUERY\"", c[EngineCodes.Firebird]); + Assert.Equal("SELECT AGGREGATE(*) AS \"aggregate\" FROM (SELECT 1 FROM \"A\" WHERE \"Column1\" IS NOT NULL AND \"Column2\" IS NOT NULL) AS \"AggregateQuery\"", c[EngineCodes.PostgreSql]); + } + + [Fact] + public void AsAggregateMultipleColumnsAlias() + { + var query = new Query("A").AsAggregate("aggregate", new[] { "Column1", "Column2" }, "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT AGGREGATE(*) AS [Alias] FROM (SELECT 1 FROM [A] WHERE [Column1] IS NOT NULL AND [Column2] IS NOT NULL) AS [AliasAggregateQuery]", c[EngineCodes.SqlServer]); + Assert.Equal("SELECT AGGREGATE(*) AS `Alias` FROM (SELECT 1 FROM `A` WHERE `Column1` IS NOT NULL AND `Column2` IS NOT NULL) AS `AliasAggregateQuery`", c[EngineCodes.MySql]); + Assert.Equal("SELECT AGGREGATE(*) AS \"ALIAS\" FROM (SELECT 1 FROM \"A\" WHERE \"COLUMN1\" IS NOT NULL AND \"COLUMN2\" IS NOT NULL) AS \"ALIASAGGREGATEQUERY\"", c[EngineCodes.Firebird]); + Assert.Equal("SELECT AGGREGATE(*) AS \"Alias\" FROM (SELECT 1 FROM \"A\" WHERE \"Column1\" IS NOT NULL AND \"Column2\" IS NOT NULL) AS \"AliasAggregateQuery\"", c[EngineCodes.PostgreSql]); + } + [Fact] public void Count() { @@ -119,6 +171,16 @@ public void Average() Assert.Equal("SELECT AVG([TTL]) AS [avg] FROM [A]", c[EngineCodes.SqlServer]); } + [Fact] + public void AverageAlias() + { + var query = new Query("A").AsAverageAs("TTL", "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT AVG([TTL]) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + } + [Fact] public void Sum() { @@ -129,6 +191,16 @@ public void Sum() Assert.Equal("SELECT SUM([PacketsDropped]) AS [sum] FROM [A]", c[EngineCodes.SqlServer]); } + [Fact] + public void SumAlias() + { + var query = new Query("A").AsSumAs("PacketsDropped", "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT SUM([PacketsDropped]) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + } + [Fact] public void Max() { @@ -139,6 +211,16 @@ public void Max() Assert.Equal("SELECT MAX([LatencyMs]) AS [max] FROM [A]", c[EngineCodes.SqlServer]); } + [Fact] + public void MaxAlias() + { + var query = new Query("A").AsMaxAs("LatencyMs", "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT MAX([LatencyMs]) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + } + [Fact] public void Min() { @@ -148,5 +230,15 @@ public void Min() Assert.Equal("SELECT MIN([LatencyMs]) AS [min] FROM [A]", c[EngineCodes.SqlServer]); } + + [Fact] + public void MinAlias() + { + var query = new Query("A").AsMinAs("LatencyMs", "Alias"); + + var c = Compile(query); + + Assert.Equal("SELECT MIN([LatencyMs]) AS [Alias] FROM [A]", c[EngineCodes.SqlServer]); + } } } diff --git a/QueryBuilder/Query.Aggregate.cs b/QueryBuilder/Query.Aggregate.cs index 15ea9a31..6d881102 100644 --- a/QueryBuilder/Query.Aggregate.cs +++ b/QueryBuilder/Query.Aggregate.cs @@ -5,6 +5,9 @@ namespace SqlKata { public partial class Query { + /********************************************************************** + ** Generic aggregate ** + **********************************************************************/ public Query AsAggregate(string type, IEnumerable columns, string alias = null) { if (columns.Count() == 0) @@ -25,6 +28,9 @@ public Query AsAggregate(string type, IEnumerable columns, string alias return this; } + /********************************************************************** + ** Count ** + **********************************************************************/ public Query AsCount(params string[] columns) { var cols = columns.ToList(); @@ -43,28 +49,50 @@ public Query AsCountAs(string column, string alias) => public Query AsCountAs(IEnumerable columns, string alias) => AsAggregate("count", columns, alias); - public Query AsAvg(string column) - { - return AsAggregate("avg", new string[] { column }); - } - public Query AsAverage(string column) - { - return AsAvg(column); - } - public Query AsSum(string column) - { - return AsAggregate("sum", new[] { column }); - } + /********************************************************************** + ** Average ** + **********************************************************************/ + public Query AsAvg(string column) => + AsAverage(column); - public Query AsMax(string column) - { - return AsAggregate("max", new[] { column }); - } + public Query AsAverage(string column) => + AsAggregate("avg", new[] { column }, null); - public Query AsMin(string column) - { - return AsAggregate("min", new[] { column }); - } + public Query AsAvgAs(string column, string alias) => + AsAverageAs(column, alias); + + public Query AsAverageAs(string column, string alias) => + AsAggregate("avg", new[] { column }, alias); + + + /********************************************************************** + ** Sum ** + **********************************************************************/ + public Query AsSum(string column) => + AsAggregate("sum", new[] { column }, null); + + public Query AsSumAs(string column, string alias = null) => + AsAggregate("sum", new[] { column }, alias); + + + /********************************************************************** + ** Maximum ** + **********************************************************************/ + public Query AsMax(string column) => + AsAggregate("max", new[] { column }, null); + + public Query AsMaxAs(string column, string alias = null) => + AsAggregate("max", new[] { column }, alias); + + + /********************************************************************** + ** Minimum ** + **********************************************************************/ + public Query AsMin(string column) => + AsAggregate("min", new[] { column }, null); + + public Query AsMinAs(string column, string alias = null) => + AsAggregate("min", new[] { column }, alias); } }