4
4
5
5
using System ;
6
6
using System . Diagnostics ;
7
+ using System . Diagnostics . CodeAnalysis ;
7
8
using System . Globalization ;
8
9
using System . Linq . Expressions ;
9
10
using System . Reflection ;
10
11
using System . Text . Json . Serialization ;
12
+
11
13
using Elastic . Transport ;
12
14
13
15
#if ELASTICSEARCH_SERVERLESS
14
16
namespace Elastic . Clients . Elasticsearch . Serverless ;
15
17
#else
18
+
16
19
namespace Elastic . Clients . Elasticsearch ;
17
20
#endif
18
21
19
22
[ JsonConverter ( typeof ( FieldConverter ) ) ]
20
- [ DebuggerDisplay ( "{" + nameof ( DebugDisplay ) + ",nq}" ) ]
21
- public sealed class Field : IEquatable < Field > , IUrlParameter
23
+ [ DebuggerDisplay ( $ "{ nameof ( DebuggerDisplay ) } ,nq") ]
24
+ public sealed class Field :
25
+ IEquatable < Field > ,
26
+ IUrlParameter
22
27
{
23
28
private readonly object _comparisonValue ;
24
- private readonly Type _type ;
29
+ private readonly Type ? _type ;
25
30
26
31
// Pseudo and metadata fields
27
32
@@ -30,143 +35,173 @@ public sealed class Field : IEquatable<Field>, IUrlParameter
30
35
public static Field KeyField = new ( "_key" ) ;
31
36
public static Field CountField = new ( "_count" ) ;
32
37
33
- public Field ( string name ) : this ( name , null , null ) { }
38
+ /// <summary>
39
+ /// The name of the field
40
+ /// </summary>
41
+ public string ? Name { get ; }
42
+
43
+ /// <summary>
44
+ /// An expression from which the name of the field can be inferred
45
+ /// </summary>
46
+ public Expression ? Expression { get ; }
47
+
48
+ /// <summary>
49
+ /// A property from which the name of the field can be inferred
50
+ /// </summary>
51
+ public PropertyInfo ? Property { get ; }
52
+
53
+ /// <summary>
54
+ /// A boost to apply to the field
55
+ /// </summary>
56
+ public double ? Boost { get ; set ; }
57
+
58
+ /// <summary>
59
+ /// A format to apply to the field.
60
+ /// </summary>
61
+ /// <remarks>
62
+ /// Can be used only for Doc Value Fields Elasticsearch 6.4.0+
63
+ /// </remarks>
64
+ public string ? Format { get ; set ; }
65
+
66
+ internal bool CachableExpression { get ; }
67
+
68
+ #region Constructors
69
+
70
+ public Field ( string name ) : this ( name , null , null )
71
+ {
72
+ }
34
73
35
- public Field ( string name , double boost ) : this ( name , boost , null ) { }
74
+ public Field ( string name , double boost ) : this ( name , boost , null )
75
+ {
76
+ }
36
77
37
- public Field ( string name , string format ) : this ( name , null , format ) { }
78
+ public Field ( string name , string format ) : this ( name , null , format )
79
+ {
80
+ }
38
81
39
82
public Field ( string name , double ? boost , string ? format )
40
83
{
41
- name . ThrowIfNullOrEmpty ( nameof ( name ) ) ;
84
+ if ( string . IsNullOrEmpty ( name ) )
85
+ throw new ArgumentException ( $ "{ name } can not be null or empty.", nameof ( name ) ) ;
86
+
42
87
Name = ParseFieldName ( name , out var b ) ;
43
88
Boost = b ?? boost ;
44
89
Format = format ;
90
+
45
91
_comparisonValue = Name ;
46
92
}
47
93
48
- public Field ( Expression expression , double ? boost = null , string format = null )
94
+ public Field ( Expression expression , double ? boost = null , string ? format = null )
49
95
{
50
96
Expression = expression ?? throw new ArgumentNullException ( nameof ( expression ) ) ;
51
97
Boost = boost ;
52
98
Format = format ;
99
+
53
100
_comparisonValue = expression . ComparisonValueFromExpression ( out var type , out var cachable ) ;
54
101
_type = type ;
102
+
55
103
CachableExpression = cachable ;
56
104
}
57
105
58
- public Field ( PropertyInfo property , double ? boost = null , string format = null )
106
+ public Field ( PropertyInfo property , double ? boost = null , string ? format = null )
59
107
{
60
108
Property = property ?? throw new ArgumentNullException ( nameof ( property ) ) ;
61
109
Boost = boost ;
62
110
Format = format ;
111
+
63
112
_comparisonValue = property ;
64
113
_type = property . DeclaringType ;
65
114
}
66
115
67
- /// <summary>
68
- /// A boost to apply to the field
69
- /// </summary>
70
- public double ? Boost { get ; set ; }
116
+ #endregion Constructors
71
117
72
- /// <summary>
73
- /// A format to apply to the field.
74
- /// </summary>
75
- /// <remarks>
76
- /// Can be used only for Doc Value Fields Elasticsearch 6.4.0+
77
- /// </remarks>
78
- public string ? Format { get ; set ; }
118
+ #region Factory Methods
79
119
80
- internal bool CachableExpression { get ; }
120
+ public static Field ? FromString ( string ? name ) => string . IsNullOrEmpty ( name ) ? null : new Field ( name ) ;
81
121
82
- /// <summary>
83
- /// An expression from which the name of the field can be inferred
84
- /// </summary>
85
- public Expression Expression { get ; }
122
+ public static Field ? FromExpression ( Expression ? expression ) => expression is null ? null : new Field ( expression ) ;
86
123
87
- /// <summary>
88
- /// The name of the field
89
- /// </summary>
90
- public string Name { get ; }
124
+ public static Field ? FromProperty ( PropertyInfo ? property ) => property is null ? null : new Field ( property ) ;
91
125
92
- /// <summary>
93
- /// A property from which the name of the field can be inferred
94
- /// </summary>
95
- public PropertyInfo Property { get ; }
126
+ #endregion Factory Methods
96
127
97
- internal string DebugDisplay =>
98
- $ "{ Expression ? . ToString ( ) ?? PropertyDebug ?? Name } { ( Boost . HasValue ? "^" + Boost . Value : string . Empty ) } "
99
- + $ "{ ( ! string . IsNullOrEmpty ( Format ) ? " format: " + Format : string . Empty ) } "
100
- + $ "{ ( _type == null ? string . Empty : " typeof: " + _type . Name ) } ";
128
+ #region Conversion Operators
101
129
102
- private string PropertyDebug => Property == null ? null : $ "PropertyInfo: { Property . Name } " ;
130
+ public static implicit operator Field ? ( string ? name ) => FromString ( name ) ;
103
131
104
- public bool Equals ( Field other ) => _type != null
105
- ? other != null && _type == other . _type && _comparisonValue . Equals ( other . _comparisonValue )
106
- : other != null && _comparisonValue . Equals ( other . _comparisonValue ) ;
132
+ public static implicit operator Field ? ( Expression ? expression ) => FromExpression ( expression ) ;
107
133
108
- string IUrlParameter . GetString ( ITransportConfiguration settings )
134
+ public static implicit operator Field ? ( PropertyInfo ? property ) => FromProperty ( property ) ;
135
+
136
+ #endregion Conversion Operators
137
+
138
+ #region Combinator Methods
139
+
140
+ public Fields And ( Field field )
109
141
{
110
- if ( settings is not IElasticsearchClientSettings elasticsearchSettings )
111
- {
112
- throw new ArgumentNullException ( nameof ( settings ) ,
113
- $ "Can not resolve { nameof ( Field ) } if no { nameof ( IElasticsearchClientSettings ) } is provided") ;
114
- }
142
+ if ( field is null )
143
+ throw new ArgumentNullException ( nameof ( field ) ) ;
115
144
116
- return GetStringCore ( elasticsearchSettings ) ;
145
+ return new ( [ this , field ] ) ;
117
146
}
118
147
119
- private string GetStringCore ( IElasticsearchClientSettings settings )
148
+ public Fields And < T , TValue > ( Expression < Func < T , TValue > > expression , double ? boost = null , string ? format = null )
120
149
{
121
- if ( settings is null )
122
- {
123
- throw new ArgumentNullException ( nameof ( settings ) ,
124
- $ "Can not resolve { nameof ( Field ) } if no { nameof ( IElasticsearchClientSettings ) } is provided") ;
125
- }
150
+ if ( expression is null )
151
+ throw new ArgumentNullException ( nameof ( expression ) ) ;
126
152
127
- return settings . Inferrer . Field ( this ) ;
153
+ return new ( [ this , new Field ( expression , boost , format ) ] ) ;
128
154
}
129
155
130
- public override string ToString ( ) => DebugDisplay ;
156
+ public Fields And < T > ( Expression < Func < T , object > > expression , double ? boost = null , string ? format = null )
157
+ {
158
+ if ( expression is null )
159
+ throw new ArgumentNullException ( nameof ( expression ) ) ;
131
160
132
- public Fields And ( Field field ) => new ( new [ ] { this , field } ) ;
161
+ return new ( [ this , new Field ( expression , boost , format ) ] ) ;
162
+ }
133
163
134
- public Fields And < T , TValue > ( Expression < Func < T , TValue > > field , double ? boost = null , string format = null )
135
- where T : class =>
136
- new ( new [ ] { this , new Field ( field , boost , format ) } ) ;
164
+ public Fields And ( string field , double ? boost = null , string ? format = null )
165
+ {
166
+ if ( field is null )
167
+ throw new ArgumentNullException ( nameof ( field ) ) ;
137
168
138
- public Fields And < T > ( Expression < Func < T , object > > field , double ? boost = null , string format = null )
139
- where T : class =>
140
- new ( new [ ] { this , new Field ( field , boost , format ) } ) ;
169
+ return new ( [ this , new Field ( field , boost , format ) ] ) ;
170
+ }
141
171
142
- public Fields And ( string field , double ? boost = null , string format = null ) =>
143
- new ( new [ ] { this , new Field ( field , boost , format ) } ) ;
172
+ public Fields And ( PropertyInfo property , double ? boost = null , string ? format = null )
173
+ {
174
+ if ( property is null )
175
+ throw new ArgumentNullException ( nameof ( property ) ) ;
144
176
145
- public Fields And ( PropertyInfo property , double ? boost = null , string format = null ) =>
146
- new ( new [ ] { this , new Field ( property , boost , format ) } ) ;
177
+ return new ( [ this , new Field ( property , boost , format ) ] ) ;
178
+ }
147
179
148
- private static string ParseFieldName ( string name , out double ? boost )
149
- {
150
- boost = null ;
151
- if ( name == null )
152
- return null ;
180
+ #endregion Combinator Methods
153
181
154
- var caretIndex = name . IndexOf ( '^' ) ;
155
- if ( caretIndex == - 1 )
156
- return name ;
182
+ #region Equality
157
183
158
- var parts = name . Split ( new [ ] { '^' } , 2 , StringSplitOptions . RemoveEmptyEntries ) ;
159
- name = parts [ 0 ] ;
160
- boost = double . Parse ( parts [ 1 ] , CultureInfo . InvariantCulture ) ;
161
- return name ;
162
- }
184
+ public static bool operator == ( Field ? a , Field ? b ) => Equals ( a , b ) ;
163
185
164
- public static implicit operator Field ( string name ) => name . IsNullOrEmpty ( ) ? null : new Field ( name ) ;
186
+ public static bool operator != ( Field ? a , Field ? b ) => ! Equals ( a , b ) ;
165
187
166
- public static implicit operator Field ( Expression expression ) =>
167
- expression == null ? null : new Field ( expression ) ;
188
+ public bool Equals ( Field ? other ) =>
189
+ other switch
190
+ {
191
+ not null when _type is not null => ( _type == other . _type ) && _comparisonValue . Equals ( other . _comparisonValue ) ,
192
+ not null when _type is null => _comparisonValue . Equals ( other . _comparisonValue ) ,
193
+ _ => false
194
+ } ;
168
195
169
- public static implicit operator Field ( PropertyInfo property ) => property == null ? null : new Field ( property ) ;
196
+ public override bool Equals ( object ? obj ) =>
197
+ obj switch
198
+ {
199
+ Field f => Equals ( f ) ,
200
+ string s => Equals ( s ) ,
201
+ Expression e => Equals ( e ) ,
202
+ PropertyInfo p => Equals ( p ) ,
203
+ _ => false
204
+ } ;
170
205
171
206
public override int GetHashCode ( )
172
207
{
@@ -178,22 +213,50 @@ public override int GetHashCode()
178
213
}
179
214
}
180
215
181
- public override bool Equals ( object obj )
216
+ #endregion Equality
217
+
218
+ #region IUrlParameter
219
+
220
+ string IUrlParameter . GetString ( ITransportConfiguration settings )
182
221
{
183
- switch ( obj )
222
+ if ( settings is not IElasticsearchClientSettings elasticsearchSettings )
184
223
{
185
- case string s :
186
- return Equals ( s ) ;
187
- case PropertyInfo p :
188
- return Equals ( p ) ;
189
- case Field f :
190
- return Equals ( f ) ;
191
- default :
192
- return false ;
224
+ throw new ArgumentNullException ( nameof ( settings ) ,
225
+ $ "Can not resolve { nameof ( Field ) } if no { nameof ( IElasticsearchClientSettings ) } is provided") ;
193
226
}
227
+
228
+ return elasticsearchSettings . Inferrer . Field ( this ) ;
194
229
}
195
230
196
- public static bool operator == ( Field x , Field y ) => Equals ( x , y ) ;
231
+ #endregion IUrlParameter
232
+
233
+ #region Debugging
234
+
235
+ public override string ToString ( ) =>
236
+ $ "{ Expression ? . ToString ( ) ?? PropertyDebug ?? Name } { ( Boost . HasValue ? "^" + Boost . Value : string . Empty ) } " +
237
+ $ "{ ( ! string . IsNullOrEmpty ( Format ) ? " format: " + Format : string . Empty ) } " +
238
+ $ "{ ( _type == null ? string . Empty : " typeof: " + _type . Name ) } ";
239
+
240
+ internal string DebuggerDisplay => ToString ( ) ;
241
+
242
+ private string ? PropertyDebug => Property is null ? null : $ "PropertyInfo: { Property . Name } ";
197
243
198
- public static bool operator != ( Field x , Field y ) => ! Equals ( x , y ) ;
244
+ #endregion Debugging
245
+
246
+ [ return : NotNullIfNotNull ( nameof ( name ) ) ]
247
+ private static string ? ParseFieldName ( string ? name , out double ? boost )
248
+ {
249
+ boost = null ;
250
+ if ( name is null )
251
+ return null ;
252
+
253
+ var caretIndex = name . IndexOf ( '^' ) ;
254
+ if ( caretIndex == - 1 )
255
+ return name ;
256
+
257
+ var parts = name . Split ( new [ ] { '^' } , 2 , StringSplitOptions . RemoveEmptyEntries ) ;
258
+ name = parts [ 0 ] ;
259
+ boost = double . Parse ( parts [ 1 ] , CultureInfo . InvariantCulture ) ;
260
+ return name ;
261
+ }
199
262
}
0 commit comments