-
-
Notifications
You must be signed in to change notification settings - Fork 126
Expand file tree
/
Copy pathMongoDbOptimizedExpressionExtensions.cs
More file actions
138 lines (112 loc) · 6.21 KB
/
MongoDbOptimizedExpressionExtensions.cs
File metadata and controls
138 lines (112 loc) · 6.21 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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) SimpleIdServer. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using MongoDB.Driver;
using System;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
namespace SimpleIdServer.Scim.Persistence.MongoDB.Extensions
{
/// <summary>
/// MongoDB-specific optimized expression extensions that avoid $expr usage for better index performance
/// </summary>
public static class MongoDbOptimizedExpressionExtensions
{
/// <summary>
/// Creates an optimized case-insensitive equality expression for MongoDB using regex instead of $expr
/// This allows MongoDB to use indexes effectively
/// </summary>
public static Expression CreateOptimizedCaseInsensitiveEqual(Expression propertyExpression, string value)
{
if (string.IsNullOrEmpty(value))
{
// For null/empty values, use direct comparison
return Expression.Equal(propertyExpression, Expression.Constant(null, typeof(string)));
}
// Escape regex special characters in the value
var escapedValue = Regex.Escape(value);
// Create case-insensitive regex pattern
var regexPattern = $"^{escapedValue}$";
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
// Use MongoDB's regex matching which can use indexes when anchored
var regexConstant = Expression.Constant(regex, typeof(Regex));
var isMatchMethod = typeof(Regex).GetMethod("IsMatch", new[] { typeof(string) });
// Handle null values by using null-conditional operator pattern
var nullCheck = Expression.Equal(propertyExpression, Expression.Constant(null, typeof(string)));
var regexMatch = Expression.Call(regexConstant, isMatchMethod, propertyExpression);
// If property is null and value is empty, return true; otherwise use regex match
if (string.IsNullOrEmpty(value))
{
return nullCheck;
}
// For non-null values, use: property != null && Regex.IsMatch(property, pattern)
var notNullCheck = Expression.NotEqual(propertyExpression, Expression.Constant(null, typeof(string)));
return Expression.AndAlso(notNullCheck, regexMatch);
}
/// <summary>
/// Creates an optimized starts-with expression for MongoDB that can use indexes
/// </summary>
public static Expression CreateOptimizedCaseInsensitiveStartsWith(Expression propertyExpression, string value)
{
if (string.IsNullOrEmpty(value))
{
// For empty value, everything starts with empty string
return Expression.Constant(true);
}
// Escape regex special characters in the value
var escapedValue = Regex.Escape(value);
// Create case-insensitive regex pattern for starts with
var regexPattern = $"^{escapedValue}";
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
var regexConstant = Expression.Constant(regex, typeof(Regex));
var isMatchMethod = typeof(Regex).GetMethod("IsMatch", new[] { typeof(string) });
// Handle null values
var notNullCheck = Expression.NotEqual(propertyExpression, Expression.Constant(null, typeof(string)));
var regexMatch = Expression.Call(regexConstant, isMatchMethod, propertyExpression);
return Expression.AndAlso(notNullCheck, regexMatch);
}
/// <summary>
/// Creates an optimized contains expression for MongoDB
/// </summary>
public static Expression CreateOptimizedCaseInsensitiveContains(Expression propertyExpression, string value)
{
if (string.IsNullOrEmpty(value))
{
// For empty value, everything contains empty string
return Expression.Constant(true);
}
// Escape regex special characters in the value
var escapedValue = Regex.Escape(value);
// Create case-insensitive regex pattern for contains
var regexPattern = escapedValue;
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
var regexConstant = Expression.Constant(regex, typeof(Regex));
var isMatchMethod = typeof(Regex).GetMethod("IsMatch", new[] { typeof(string) });
// Handle null values
var notNullCheck = Expression.NotEqual(propertyExpression, Expression.Constant(null, typeof(string)));
var regexMatch = Expression.Call(regexConstant, isMatchMethod, propertyExpression);
return Expression.AndAlso(notNullCheck, regexMatch);
}
/// <summary>
/// Creates an optimized ends-with expression for MongoDB
/// </summary>
public static Expression CreateOptimizedCaseInsensitiveEndsWith(Expression propertyExpression, string value)
{
if (string.IsNullOrEmpty(value))
{
// For empty value, everything ends with empty string
return Expression.Constant(true);
}
// Escape regex special characters in the value
var escapedValue = Regex.Escape(value);
// Create case-insensitive regex pattern for ends with
var regexPattern = $"{escapedValue}$";
var regex = new Regex(regexPattern, RegexOptions.IgnoreCase);
var regexConstant = Expression.Constant(regex, typeof(Regex));
var isMatchMethod = typeof(Regex).GetMethod("IsMatch", new[] { typeof(string) });
// Handle null values
var notNullCheck = Expression.NotEqual(propertyExpression, Expression.Constant(null, typeof(string)));
var regexMatch = Expression.Call(regexConstant, isMatchMethod, propertyExpression);
return Expression.AndAlso(notNullCheck, regexMatch);
}
}
}