-
-
Notifications
You must be signed in to change notification settings - Fork 163
Expand file tree
/
Copy pathLogicalExpression.cs
More file actions
116 lines (93 loc) · 3.01 KB
/
LogicalExpression.cs
File metadata and controls
116 lines (93 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System.Collections.Immutable;
using System.Text;
using Humanizer;
using JetBrains.Annotations;
namespace JsonApiDotNetCore.Queries.Expressions;
/// <summary>
/// This expression allows to test whether one or all of its boolean operands are true. It represents the logical AND/OR filter functions, resulting from
/// text such as:
/// <c>
/// and(equals(title,'Work'),has(articles))
/// </c>
/// , or:
/// <c>
/// or(equals(title,'Work'),has(articles))
/// </c>
/// .
/// </summary>
[PublicAPI]
public class LogicalExpression : FilterExpression
{
/// <summary>
/// The operator used to compare <see cref="Terms" />.
/// </summary>
public LogicalOperator Operator { get; }
/// <summary>
/// The list of one or more boolean operands.
/// </summary>
public IImmutableList<FilterExpression> Terms { get; }
public LogicalExpression(LogicalOperator @operator, params FilterExpression[] terms)
: this(@operator, terms.ToImmutableArray())
{
}
public LogicalExpression(LogicalOperator @operator, IImmutableList<FilterExpression> terms)
{
ArgumentNullException.ThrowIfNull(terms);
if (terms.Count < 2)
{
throw new ArgumentException("At least two terms are required.", nameof(terms));
}
Operator = @operator;
Terms = terms;
}
public static FilterExpression? Compose(LogicalOperator @operator, params FilterExpression?[] filters)
{
ArgumentNullException.ThrowIfNull(filters);
ImmutableArray<FilterExpression> terms = [.. filters.WhereNotNull()];
return terms.Length > 1 ? new LogicalExpression(@operator, terms) : terms.FirstOrDefault();
}
public override TResult Accept<TArgument, TResult>(QueryExpressionVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitLogical(this, argument);
}
public override string ToString()
{
return InnerToString(false);
}
public override string ToFullString()
{
return InnerToString(true);
}
private string InnerToString(bool toFullString)
{
var builder = new StringBuilder();
builder.Append(Operator.ToString().Camelize());
builder.Append('(');
builder.Append(string.Join(",", Terms.Select(term => toFullString ? term.ToFullString() : term.ToString())));
builder.Append(')');
return builder.ToString();
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj is null || GetType() != obj.GetType())
{
return false;
}
var other = (LogicalExpression)obj;
return Operator == other.Operator && Terms.SequenceEqual(other.Terms);
}
public override int GetHashCode()
{
var hashCode = new HashCode();
hashCode.Add(Operator);
foreach (QueryExpression term in Terms)
{
hashCode.Add(term);
}
return hashCode.ToHashCode();
}
}