-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
943 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
...elational/EntityFrameworkCore/Query/SqlExpressions/WindowFunctionPartitionByExpression.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using System.Linq.Expressions; | ||
using Microsoft.EntityFrameworkCore.Query; | ||
using Microsoft.EntityFrameworkCore.Query.SqlExpressions; | ||
using Microsoft.EntityFrameworkCore.Storage; | ||
|
||
namespace Thinktecture.EntityFrameworkCore.Query.SqlExpressions; | ||
|
||
/// <summary> | ||
/// Represents PARTITION BY. | ||
/// </summary> | ||
public class WindowFunctionPartitionByExpression : SqlExpression, INotNullableSqlExpression | ||
{ | ||
/// <summary> | ||
/// Partition by expressions. | ||
/// </summary> | ||
public IReadOnlyList<SqlExpression> PartitionBy { get; } | ||
|
||
/// <inheritdoc /> | ||
public WindowFunctionPartitionByExpression(IReadOnlyList<SqlExpression> partitionBy) | ||
: base(typeof(WindowFunctionPartitionByClause), RelationalTypeMapping.NullMapping) | ||
{ | ||
PartitionBy = partitionBy ?? throw new ArgumentNullException(nameof(partitionBy)); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override Expression Accept(ExpressionVisitor visitor) | ||
{ | ||
if (visitor is QuerySqlGenerator) | ||
throw new NotSupportedException("The window function contains some expressions not supported by the Entity Framework."); | ||
|
||
return base.Accept(visitor); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override Expression VisitChildren(ExpressionVisitor visitor) | ||
{ | ||
var visited = visitor.VisitExpressions(PartitionBy); | ||
|
||
return ReferenceEquals(visited, PartitionBy) ? this : new WindowFunctionPartitionByExpression(visited); | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override void Print(ExpressionPrinter expressionPrinter) | ||
{ | ||
ArgumentNullException.ThrowIfNull(expressionPrinter); | ||
|
||
expressionPrinter.VisitCollection(PartitionBy); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override bool Equals(object? obj) | ||
{ | ||
return obj != null && (ReferenceEquals(this, obj) || Equals(obj as WindowFunctionPartitionByExpression)); | ||
} | ||
|
||
private bool Equals(WindowFunctionPartitionByExpression? expression) | ||
{ | ||
return base.Equals(expression) && PartitionBy.SequenceEqual(expression.PartitionBy); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override int GetHashCode() | ||
{ | ||
var hash = new HashCode(); | ||
hash.Add(base.GetHashCode()); | ||
|
||
for (var i = 0; i < PartitionBy.Count; i++) | ||
{ | ||
hash.Add(PartitionBy[i]); | ||
} | ||
|
||
return hash.ToHashCode(); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...ure.EntityFrameworkCore.Relational/EntityFrameworkCore/WindowFunctionPartitionByClause.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Thinktecture.EntityFrameworkCore; | ||
|
||
/// <summary> | ||
/// Helper class to attach extension methods to. | ||
/// </summary> | ||
public sealed class WindowFunctionPartitionByClause | ||
{ | ||
private WindowFunctionPartitionByClause() | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
src/Thinktecture.EntityFrameworkCore.Relational/Extensions/WindowFunction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
using System.Text.RegularExpressions; | ||
|
||
namespace Thinktecture; | ||
|
||
/// <summary> | ||
/// Represents a window function name. | ||
/// </summary> | ||
public abstract partial class WindowFunction | ||
{ | ||
private const string _REGEX_PATTERN = "^[A-Z_]+$"; | ||
private const RegexOptions _REGEX_OPTIONS = RegexOptions.IgnoreCase | RegexOptions.Compiled; | ||
|
||
[GeneratedRegex(_REGEX_PATTERN, _REGEX_OPTIONS)] | ||
private static partial Regex ValidateName(); | ||
|
||
/// <summary> | ||
/// Name of the function. | ||
/// </summary> | ||
public string Name { get; } | ||
|
||
/// <summary> | ||
/// Return type of the function. | ||
/// </summary> | ||
public Type ReturnType { get; } | ||
|
||
/// <summary> | ||
/// Indication whether to use '*' when no arguments are provided. | ||
/// </summary> | ||
public bool UseStarWhenNoArguments { get; } | ||
|
||
/// <summary> | ||
/// Initializes a new instance of <see cref="WindowFunction"/>. | ||
/// </summary> | ||
/// <param name="name">The name of the window function.</param> | ||
/// <param name="returnType">Return type of the function.</param> | ||
/// <param name="useStarWhenNoArguments">Indication whether to use '*' when no arguments are provided.</param> | ||
protected WindowFunction(string name, Type returnType, bool useStarWhenNoArguments) | ||
{ | ||
Name = EnsureValidName(name); | ||
ReturnType = returnType ?? throw new ArgumentNullException(nameof(returnType)); | ||
UseStarWhenNoArguments = useStarWhenNoArguments; | ||
} | ||
|
||
private static string EnsureValidName(string name) | ||
{ | ||
if (String.IsNullOrWhiteSpace(name)) | ||
throw new ArgumentException("Name must not be empty."); | ||
|
||
name = name.Trim(); | ||
|
||
if (!ValidateName().IsMatch(name)) | ||
throw new ArgumentException("The name must consist of characters A-Z and may contain an underscore."); | ||
|
||
return name; | ||
} | ||
|
||
/// <summary> | ||
/// Deconstruction of the window function. | ||
/// </summary> | ||
/// <param name="name">The name of the function.</param> | ||
/// <param name="returnType">The return type of the function.</param> | ||
/// <param name="useStarWhenNoArguments">Indication whether to use '*' when no arguments are provided.</param> | ||
public void Deconstruct(out string name, out Type returnType, out bool useStarWhenNoArguments) | ||
{ | ||
name = Name; | ||
returnType = ReturnType; | ||
useStarWhenNoArguments = UseStarWhenNoArguments; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Represents a window function name. | ||
/// </summary> | ||
public sealed class WindowFunction<TResult> : WindowFunction, IEquatable<WindowFunction<TResult>> | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of <see cref="WindowFunction{TResult}"/>. | ||
/// </summary> | ||
/// <param name="name">The name of the window function</param> | ||
/// <param name="useStarWhenNoArguments">Indication whether to use '*' when no arguments are provided.</param> | ||
public WindowFunction( | ||
string name, | ||
bool useStarWhenNoArguments = false) | ||
: base(name, typeof(TResult), useStarWhenNoArguments) | ||
{ | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override bool Equals(object? obj) | ||
{ | ||
return Equals(obj as WindowFunction<TResult>); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public bool Equals(WindowFunction<TResult>? other) | ||
{ | ||
if (ReferenceEquals(null, other)) | ||
return false; | ||
if (ReferenceEquals(this, other)) | ||
return true; | ||
|
||
return Name == other.Name; | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override int GetHashCode() | ||
{ | ||
return Name.GetHashCode(); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public override string ToString() | ||
{ | ||
return Name; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.