Skip to content

Commit e565704

Browse files
fixup! Support evaluation of Random.Next and NextDouble on db side
Add an option for failing or falling back in case of lack of dialect support
1 parent 3a6a13f commit e565704

File tree

3 files changed

+231
-311
lines changed

3 files changed

+231
-311
lines changed

src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs

Lines changed: 51 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -43,195 +43,76 @@ protected override void Configure(Configuration configuration)
4343
configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString());
4444
}
4545

46-
[Test]
47-
public async Task CanQueryByRandomDoubleAsync()
48-
{
49-
using (var spy = new SqlLogSpy())
50-
{
51-
var random = new Random();
52-
var x = await (db.Orders.CountAsync(o => o.OrderId > random.NextDouble()));
53-
54-
Assert.That(x, Is.GreaterThan(0));
55-
AssertFunctionInSql("random", spy);
56-
}
57-
}
58-
59-
[Test]
60-
public async Task CanSelectRandomDoubleAsync()
61-
{
62-
using (var spy = new SqlLogSpy())
63-
{
64-
var random = new Random();
65-
var x =
66-
await (db
67-
.Orders.Select(o => new { id = o.OrderId, r = random.NextDouble() })
68-
.OrderBy(o => o.id).ToListAsync());
69-
70-
Assert.That(x, Has.Count.GreaterThan(0));
71-
var randomValues = x.Select(o => o.r).Distinct().ToArray();
72-
Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(1));
73-
74-
if (!LegacyPreEvaluation && IsFunctionSupported("random"))
75-
{
76-
// Naïve randomness check
77-
Assert.That(
78-
randomValues,
79-
Has.Length.GreaterThan(x.Count / 2),
80-
"Generated values do not seem very random");
81-
}
82-
83-
AssertFunctionInSql("random", spy);
84-
}
85-
}
86-
8746
[Test]
8847
public async Task CanQueryByRandomIntAsync()
8948
{
49+
var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor");
9050
var idMin = await (db.Orders.MinAsync(o => o.OrderId));
91-
using (var spy = new SqlLogSpy())
92-
{
93-
var random = new Random();
94-
// Dodge a Firebird driver limitation by putting the constants before the order id.
95-
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
96-
// knowing the type of the condition. For some reasons the driver considers the casting should not be
97-
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
98-
// Firebird complain, so moving the constants on the left side have been put before the order id, in
99-
// order for these constants to be casted by the driver.
100-
var x = await (db.Orders.CountAsync(o => -idMin - 1 + o.OrderId < random.Next()));
101-
102-
Assert.That(x, Is.GreaterThan(0));
103-
// Next requires support of both floor and rand
104-
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
105-
}
106-
}
107-
108-
[Test]
109-
public async Task CanSelectRandomIntAsync()
110-
{
111-
using (var spy = new SqlLogSpy())
112-
{
113-
var random = new Random();
114-
var x =
115-
await (db
116-
.Orders.Select(o => new { id = o.OrderId, r = random.Next() })
117-
.OrderBy(o => o.id).ToListAsync());
118-
119-
Assert.That(x, Has.Count.GreaterThan(0));
120-
var randomValues = x.Select(o => o.r).Distinct().ToArray();
121-
Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(int.MaxValue).And.TypeOf<int>());
122-
123-
if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor"))
51+
RunTest(
52+
isSupported,
53+
spy =>
12454
{
125-
// Naïve randomness check
126-
Assert.That(
127-
randomValues,
128-
Has.Length.GreaterThan(x.Count / 2),
129-
"Generated values do not seem very random");
130-
}
131-
132-
// Next requires support of both floor and rand
133-
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
134-
}
55+
var random = new Random();
56+
// Dodge a Firebird driver limitation by putting the constants before the order id.
57+
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
58+
// knowing the type of the condition. For some reasons the driver considers the casting should not be
59+
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
60+
// Firebird complain, so moving the constants on the left side have been put before the order id, in
61+
// order for these constants to be casted by the driver.
62+
var x = db.Orders.Count(o => -idMin - 1 + o.OrderId < random.Next());
63+
64+
Assert.That(x, Is.GreaterThan(0));
65+
// Next requires support of both floor and rand
66+
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
67+
});
13568
}
13669

13770
[Test]
13871
public async Task CanQueryByRandomIntWithMaxAsync()
13972
{
73+
var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor");
14074
var idMin = await (db.Orders.MinAsync(o => o.OrderId));
141-
using (var spy = new SqlLogSpy())
142-
{
143-
var random = new Random();
144-
// Dodge a Firebird driver limitation by putting the constants before the order id.
145-
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
146-
// knowing the type of the condition. For some reasons the driver considers the casting should not be
147-
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
148-
// Firebird complain, so moving the constants on the left side have been put before the order id, in
149-
// order for these constants to be casted by the driver.
150-
var x = await (db.Orders.CountAsync(o => -idMin + o.OrderId <= random.Next(10)));
151-
152-
Assert.That(x, Is.GreaterThan(0).And.LessThan(11));
153-
// Next requires support of both floor and rand
154-
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
155-
}
156-
}
157-
158-
[Test]
159-
public async Task CanSelectRandomIntWithMaxAsync()
160-
{
161-
using (var spy = new SqlLogSpy())
162-
{
163-
var random = new Random();
164-
var x =
165-
await (db
166-
.Orders.Select(o => new { id = o.OrderId, r = random.Next(10) })
167-
.OrderBy(o => o.id).ToListAsync());
168-
169-
Assert.That(x, Has.Count.GreaterThan(0));
170-
var randomValues = x.Select(o => o.r).Distinct().ToArray();
171-
Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(10).And.TypeOf<int>());
172-
173-
if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor"))
75+
RunTest(
76+
isSupported,
77+
spy =>
17478
{
175-
// Naïve randomness check
176-
Assert.That(
177-
randomValues,
178-
Has.Length.GreaterThan(Math.Min(10, x.Count) / 2),
179-
"Generated values do not seem very random");
180-
}
181-
182-
// Next requires support of both floor and rand
183-
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
184-
}
79+
var random = new Random();
80+
// Dodge a Firebird driver limitation by putting the constants before the order id.
81+
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
82+
// knowing the type of the condition. For some reasons the driver considers the casting should not be
83+
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
84+
// Firebird complain, so moving the constants on the left side have been put before the order id, in
85+
// order for these constants to be casted by the driver.
86+
var x = db.Orders.Count(o => -idMin + o.OrderId <= random.Next(10));
87+
88+
Assert.That(x, Is.GreaterThan(0).And.LessThan(11));
89+
// Next requires support of both floor and rand
90+
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
91+
});
18592
}
18693

18794
[Test]
18895
public async Task CanQueryByRandomIntWithMinMaxAsync()
18996
{
97+
var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor");
19098
var idMin = await (db.Orders.MinAsync(o => o.OrderId));
191-
using (var spy = new SqlLogSpy())
192-
{
193-
var random = new Random();
194-
// Dodge a Firebird driver limitation by putting the constants before the order id.
195-
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
196-
// knowing the type of the condition. For some reasons the driver considers the casting should not be
197-
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
198-
// Firebird complain, so moving the constants on the left side have been put before the order id, in
199-
// order for these constants to be casted by the driver.
200-
var x = await (db.Orders.CountAsync(o => -idMin + o.OrderId < random.Next(1, 10)));
201-
202-
Assert.That(x, Is.GreaterThan(0).And.LessThan(10));
203-
// Next requires support of both floor and rand
204-
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
205-
}
206-
}
207-
208-
[Test]
209-
public async Task CanSelectRandomIntWithMinMaxAsync()
210-
{
211-
using (var spy = new SqlLogSpy())
212-
{
213-
var random = new Random();
214-
var x =
215-
await (db
216-
.Orders.Select(o => new { id = o.OrderId, r = random.Next(1, 11) })
217-
.OrderBy(o => o.id).ToListAsync());
218-
219-
Assert.That(x, Has.Count.GreaterThan(0));
220-
var randomValues = x.Select(o => o.r).Distinct().ToArray();
221-
Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.LessThan(11).And.TypeOf<int>());
222-
223-
if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor"))
99+
RunTest(
100+
isSupported,
101+
spy =>
224102
{
225-
// Naïve randomness check
226-
Assert.That(
227-
randomValues,
228-
Has.Length.GreaterThan(Math.Min(10, x.Count) / 2),
229-
"Generated values do not seem very random");
230-
}
231-
232-
// Next requires support of both floor and rand
233-
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
234-
}
103+
var random = new Random();
104+
// Dodge a Firebird driver limitation by putting the constants before the order id.
105+
// This driver cast parameters to their types in some cases for avoiding Firebird complaining of not
106+
// knowing the type of the condition. For some reasons the driver considers the casting should not be
107+
// done next to the conditional operator. Having the cast only on one side is enough for avoiding
108+
// Firebird complain, so moving the constants on the left side have been put before the order id, in
109+
// order for these constants to be casted by the driver.
110+
var x = db.Orders.Count(o => -idMin + o.OrderId < random.Next(1, 10));
111+
112+
Assert.That(x, Is.GreaterThan(0).And.LessThan(10));
113+
// Next requires support of both floor and rand
114+
AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy);
115+
});
235116
}
236117

237118
private void RunTest(bool isSupported, Action<SqlLogSpy> test)

0 commit comments

Comments
 (0)