Skip to content

Commit bf4cd0b

Browse files
committed
Merge ConditionalsProjection to ConditionalProjection
1 parent 79a9eee commit bf4cd0b

File tree

5 files changed

+169
-329
lines changed

5 files changed

+169
-329
lines changed

src/NHibernate.Test/Async/Criteria/ConditionalProjectionTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public async Task UsingMultiConditionalsAsync()
7979
// ... else 99
8080
var elseProjection = Projections.Constant("99");
8181

82-
var conditionalsProjection = Projections.Conditionals(criterionProjections, elseProjection);
82+
var conditionalsProjection = Projections.Conditional(criterionProjections, elseProjection);
8383

8484
var order = Order.Asc(conditionalsProjection);
8585

src/NHibernate.Test/Criteria/ConditionalProjectionTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public void UsingMultiConditionals()
6868
// ... else 99
6969
var elseProjection = Projections.Constant("99");
7070

71-
var conditionalsProjection = Projections.Conditionals(criterionProjections, elseProjection);
71+
var conditionalsProjection = Projections.Conditional(criterionProjections, elseProjection);
7272

7373
var order = Order.Asc(conditionalsProjection);
7474

Lines changed: 164 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,222 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using NHibernate.Engine;
4+
using NHibernate.SqlCommand;
5+
using NHibernate.Type;
6+
17
namespace NHibernate.Criterion
28
{
3-
using System;
4-
using System.Collections.Generic;
5-
using Engine;
6-
using SqlCommand;
7-
using Type;
8-
9+
/// <summary>
10+
/// Defines a "switch" projection which supports multiple "cases" ("when/then's").
11+
/// </summary>
12+
/// <seealso cref="SimpleProjection" />
13+
/// <seealso cref="ConditionalProjectionCase" />
914
[Serializable]
1015
public class ConditionalProjection : SimpleProjection
1116
{
12-
private readonly ICriterion criterion;
13-
private readonly IProjection whenTrue;
14-
private readonly IProjection whenFalse;
17+
private readonly ConditionalProjectionCase[] _cases;
18+
private readonly IProjection _elseProjection;
1519

20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="ConditionalProjection"/> class.
22+
/// </summary>
23+
/// <param name="criterion">The <see cref="ICriterion"/></param>
24+
/// <param name="whenTrue">The true <see cref="IProjection"/></param>
25+
/// <param name="whenFalse">The else <see cref="IProjection"/>.</param>
1626
public ConditionalProjection(ICriterion criterion, IProjection whenTrue, IProjection whenFalse)
1727
{
18-
this.whenTrue = whenTrue;
19-
this.whenFalse = whenFalse;
20-
this.criterion = criterion;
28+
_elseProjection = whenFalse;
29+
_cases = new[] {new ConditionalProjectionCase(criterion, whenTrue)};
30+
}
31+
32+
/// <summary>
33+
/// Initializes a new instance of the <see cref="ConditionalProjection"/> class.
34+
/// </summary>
35+
/// <param name="cases">The <see cref="ConditionalProjectionCase"/>s containing <see cref="ICriterion"/> and <see cref="IProjection"/> pairs.</param>
36+
/// <param name="elseProjection">The else <see cref="IProjection"/>.</param>
37+
public ConditionalProjection(ConditionalProjectionCase[] cases, IProjection elseProjection)
38+
{
39+
if (cases == null)
40+
throw new ArgumentNullException(nameof(cases));
41+
if (cases.Length == 0)
42+
throw new ArgumentException("Array should not be empty.", nameof(cases));
43+
44+
_cases = cases;
45+
_elseProjection = elseProjection;
2146
}
2247

2348
public override bool IsAggregate
2449
{
2550
get
2651
{
27-
IProjection[] projections = criterion.GetProjections();
28-
if(projections != null)
52+
if (_elseProjection.IsAggregate)
53+
return true;
54+
55+
foreach (var projectionCase in _cases)
2956
{
30-
foreach (IProjection projection in projections)
57+
if (projectionCase.Projection.IsAggregate)
58+
return true;
59+
60+
var projections = projectionCase.Criterion.GetProjections();
61+
if (projections != null)
3162
{
32-
if (projection.IsAggregate)
33-
return true;
63+
foreach (var projection in projections)
64+
{
65+
if (projection.IsAggregate)
66+
{
67+
return true;
68+
}
69+
}
3470
}
3571
}
36-
if(whenFalse.IsAggregate)
37-
return true;
38-
if(whenTrue.IsAggregate)
72+
73+
return false;
74+
}
75+
}
76+
77+
public override bool IsGrouped
78+
{
79+
get
80+
{
81+
if (_elseProjection.IsGrouped)
3982
return true;
83+
84+
foreach (var projectionCase in _cases)
85+
{
86+
if (projectionCase.Projection.IsGrouped)
87+
return true;
88+
89+
var projections = projectionCase.Criterion.GetProjections();
90+
if (projections != null)
91+
{
92+
foreach (var projection in projections)
93+
{
94+
if (projection.IsGrouped)
95+
return true;
96+
}
97+
}
98+
}
99+
40100
return false;
41101
}
42102
}
43103

44104
public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery)
45105
{
46-
SqlString condition = criterion.ToSqlString(criteria, criteriaQuery);
47-
var ifTrue = CriterionUtil.GetColumnNameAsSqlStringPart(whenTrue, criteriaQuery, criteria);
48-
var ifFalse = CriterionUtil.GetColumnNameAsSqlStringPart(whenFalse, criteriaQuery, criteria);
49-
return new SqlString("(case when ", condition, " then ", ifTrue, " else ", ifFalse, " end) as ",
50-
GetColumnAlias(position));
106+
var sqlBuilder = new SqlStringBuilder(5 + (_cases.Length * 4));
107+
108+
sqlBuilder.Add("(case");
109+
110+
foreach (var projectionCase in _cases)
111+
{
112+
sqlBuilder.Add(" when ");
113+
sqlBuilder.Add(projectionCase.Criterion.ToSqlString(criteria, criteriaQuery));
114+
sqlBuilder.Add(" then ");
115+
sqlBuilder.AddObject(CriterionUtil.GetColumnNameAsSqlStringPart(projectionCase.Projection, criteriaQuery, criteria));
116+
}
117+
118+
sqlBuilder.Add(" else ");
119+
sqlBuilder.AddObject(CriterionUtil.GetColumnNameAsSqlStringPart(_elseProjection, criteriaQuery, criteria));
120+
121+
sqlBuilder.Add(" end) as ");
122+
sqlBuilder.Add(GetColumnAlias(position));
123+
124+
return sqlBuilder.ToSqlString();
51125
}
52126

53127
public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
54128
{
55-
IType[] trueTypes = whenTrue.GetTypes(criteria, criteriaQuery);
56-
IType[] falseTypes = whenFalse.GetTypes(criteria, criteriaQuery);
129+
var elseTypes = _elseProjection.GetTypes(criteria, criteriaQuery);
57130

58-
bool areEqual = trueTypes.Length == falseTypes.Length;
59-
if (areEqual)
131+
for (var i = 0; i < _cases.Length; i++)
60132
{
61-
for (int i = 0; i < trueTypes.Length; i++)
133+
var subsequentTypes = _cases[i].Projection.GetTypes(criteria, criteriaQuery);
134+
if (!AreTypesEqual(elseTypes, subsequentTypes))
62135
{
63-
if(trueTypes[i].ReturnedClass != falseTypes[i].ReturnedClass)
64-
{
65-
areEqual = false;
66-
break;
67-
}
136+
string msg = "All projections must return the same types." + Environment.NewLine +
137+
"But Else projection returns: [" + string.Join<IType>(", ", elseTypes) + "] " + Environment.NewLine +
138+
"And When projection " + i + " returns: [" + string.Join<IType>(", ", subsequentTypes) + "]";
139+
140+
throw new HibernateException(msg);
68141
}
69142
}
70-
if(areEqual == false)
71-
{
72-
string msg = "Both true and false projections must return the same types."+ Environment.NewLine +
73-
"But True projection returns: ["+string.Join<IType>(", ", trueTypes) +"] "+ Environment.NewLine+
74-
"And False projection returns: ["+string.Join<IType>(", ", falseTypes)+ "]";
75143

76-
throw new HibernateException(msg);
144+
return elseTypes;
145+
}
146+
147+
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
148+
{
149+
var typedValues = new List<TypedValue>();
150+
151+
foreach (var projectionCase in _cases)
152+
{
153+
typedValues.AddRange(projectionCase.Criterion.GetTypedValues(criteria, criteriaQuery));
154+
typedValues.AddRange(projectionCase.Projection.GetTypedValues(criteria, criteriaQuery));
77155
}
78156

79-
return trueTypes;
157+
typedValues.AddRange(_elseProjection.GetTypedValues(criteria, criteriaQuery));
158+
159+
return typedValues.ToArray();
80160
}
81161

82-
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
162+
public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
83163
{
84-
List<TypedValue> tv = new List<TypedValue>();
85-
tv.AddRange(criterion.GetTypedValues(criteria, criteriaQuery));
86-
tv.AddRange(whenTrue.GetTypedValues(criteria, criteriaQuery));
87-
tv.AddRange(whenFalse.GetTypedValues(criteria, criteriaQuery));
88-
return tv.ToArray();
164+
var sqlBuilder = new SqlStringBuilder();
165+
166+
foreach (var projection in _cases)
167+
{
168+
AddToGroupedSql(sqlBuilder, projection.Criterion.GetProjections(), criteria, criteriaQuery);
169+
AddToGroupedSql(sqlBuilder, projection.Projection, criteria, criteriaQuery);
170+
}
171+
172+
AddToGroupedSql(sqlBuilder, _elseProjection, criteria, criteriaQuery);
173+
174+
// Remove last comma
175+
if (sqlBuilder.Count >= 2)
176+
{
177+
sqlBuilder.RemoveAt(sqlBuilder.Count - 1);
178+
}
179+
180+
return sqlBuilder.ToSqlString();
89181
}
90182

91-
public override bool IsGrouped
183+
private static bool AreTypesEqual(IType[] types1, IType[] types2)
92184
{
93-
get
185+
bool areEqual = types1.Length == types2.Length;
186+
if (!areEqual)
187+
{
188+
return false;
189+
}
190+
191+
for (int i = 0; i < types1.Length; i++)
94192
{
95-
IProjection[] projections = criterion.GetProjections();
96-
if(projections != null)
193+
if (types1[i].ReturnedClass != types2[i].ReturnedClass)
97194
{
98-
foreach (IProjection projection in projections)
99-
{
100-
if (projection.IsGrouped)
101-
return true;
102-
}
195+
return false;
103196
}
104-
if(whenFalse.IsGrouped)
105-
return true;
106-
if(whenTrue.IsGrouped)
107-
return true;
108-
return false;
109197
}
198+
199+
return true;
110200
}
111201

112-
public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
202+
private void AddToGroupedSql(SqlStringBuilder sqlBuilder, IProjection[] projections, ICriteria criteria, ICriteriaQuery criteriaQuery)
113203
{
114-
SqlStringBuilder buf = new SqlStringBuilder();
115-
IProjection[] projections = criterion.GetProjections();
116-
if(projections != null)
204+
if (projections == null)
205+
return;
206+
207+
foreach (var projection in projections)
117208
{
118-
foreach (IProjection proj in projections)
119-
{
120-
if (proj.IsGrouped)
121-
{
122-
buf.Add(proj.ToGroupSqlString(criteria, criteriaQuery)).Add(", ");
123-
}
124-
}
209+
AddToGroupedSql(sqlBuilder, projection, criteria, criteriaQuery);
125210
}
126-
if(whenFalse.IsGrouped)
127-
buf.Add(whenFalse.ToGroupSqlString(criteria, criteriaQuery)).Add(", ");
128-
if(whenTrue.IsGrouped)
129-
buf.Add(whenTrue.ToGroupSqlString(criteria, criteriaQuery)).Add(", ");
211+
}
130212

131-
if(buf.Count >= 2)
213+
private void AddToGroupedSql(SqlStringBuilder sqlBuilder, IProjection projection, ICriteria criteria, ICriteriaQuery criteriaQuery)
214+
{
215+
if (projection.IsGrouped)
132216
{
133-
buf.RemoveAt(buf.Count - 1);
217+
sqlBuilder.Add(projection.ToGroupSqlString(criteria, criteriaQuery));
218+
sqlBuilder.Add(", ");
134219
}
135-
return buf.ToSqlString();
136220
}
137221
}
138222
}

0 commit comments

Comments
 (0)