-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathSearchBuilderOptions.cs
293 lines (254 loc) · 9.91 KB
/
SearchBuilderOptions.cs
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
using System;
using System.Collections.Generic;
using System.Linq;
using DataTables.EditorUtil;
namespace DataTables
{
/// <summary>
/// The SearchBuilderOptions class provides a convenient method of specifying where Editor
/// should get the list of options for SearchBuilder options list.
/// This is normally from a table that is _left joined_ to the main table being
/// edited, and a list of the values available from the joined table is shown to
/// the end user to let them select from.
///
/// `SearchBuilderOptions` instances are used with the `Field.SearchBuilderOptions()` method.
/// </summary>
public class SearchBuilderOptions
{
private string _table;
private string _value;
private IEnumerable<string> _label;
private Func<string, string> _renderer;
private Action<Query> _where;
private string _order;
private List<LeftJoin> _leftJoin = new List<LeftJoin>();
private Dictionary<string, string> _fromEnum = new Dictionary<string, string>();
/// <summary>
/// Get the column name(s) for the options label
/// </summary>
/// <returns>Column name(s)</returns>
public IEnumerable<string> Label()
{
return _label;
}
/// <summary>
/// Set the column name for the SearchBuilderOptions label
/// </summary>
/// <param name="label">Column name</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Label(string label)
{
var list = new List<string> {label};
_label = list;
return this;
}
/// <summary>
/// Set multiple column names for the SearchBuilderOptions label
/// </summary>
/// <param name="label">Column names</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Label(IEnumerable<string> label)
{
_label = label;
return this;
}
/// <summary>
/// Get the order by clause for the SearchBuilderOptions
/// </summary>
/// <returns>Order by string</returns>
public string Order()
{
return _order;
}
/// <summary>
/// Set the order by clause for the SearchBuilderOptions
/// </summary>
/// <param name="order">Order by SQL statement</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Order(string order)
{
_order = order;
return this;
}
/// <summary>
/// Get the rendering function
/// </summary>
/// <returns>Rendering function</returns>
public Func<string, string> Render()
{
return _renderer;
}
/// <summary>
/// Set the rendering function for the SearchBuilderOption labels
/// </summary>
/// <param name="renderer">Rendering function. Called once for each option</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Render(Func<string, string> renderer)
{
_renderer = renderer;
return this;
}
/// <summary>
/// Get the table configured to read the options from
/// </summary>
/// <returns>Table name</returns>
public string Table()
{
return _table;
}
/// <summary>
/// Set the table to read the SearchBuilderOptions from
/// </summary>
/// <param name="table">Table name</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Table(string table)
{
_table = table;
return this;
}
/// <summary>
/// Get the value column name
/// </summary>
/// <returns>Value column name</returns>
public string Value()
{
return _value;
}
/// <summary>
/// Set the value column name
/// </summary>
/// <param name="value">Column name</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Value(string value)
{
_value = value;
return this;
}
/// <summary>
/// Get the WHERE function used to apply conditions to the SearchBuilderOptions select
/// </summary>
/// <returns>Function</returns>
public Action<Query> Where()
{
return _where;
}
/// <summary>
/// Set a function that will be used to apply conditions to the SearchBuilderOptions select
/// </summary>
/// <param name="where">Function that will add conditions to the query</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions Where(Action<Query> where)
{
_where = where;
return this;
}
/// <summary>
/// Set a function that will be used to apply a leftJoin to the SearchBuilder select
/// </summary>
/// <param name="table">String representing the table for the leftJoin</param>
/// <param name="field1">String representing the first Field for the leftJoin</param>
/// <param name="op">String representing the operatore for the leftJoin</param>
/// <param name="field2">String representing the second Field for the leftJoin</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions LeftJoin(string table, string field1, string op, string field2)
{
_leftJoin.Add(new LeftJoin(table, field1, op, field2));
return this;
}
/// <summary>
/// Set an enum that will be used to apply items to the SearchBuilder select
/// </summary>
/// <param name="useValueAsKey">Boolean to use the enum value as the key (default true)</param>
/// <returns>Self for chaining</returns>
public SearchBuilderOptions FromEnum<T>(bool useValueAsKey = true)
{
_fromEnum = Enums.ConvertToStringDictionary<T>(useValueAsKey);
return this;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/// <summary>
/// Execute the configuration, getting the SearchBuilderOptions from the database and formatting
/// for output.
/// </summary>
/// <param name="fieldIn">Field that the SearchBuilder options are to be found for</param>
/// <param name="editor">Editor Instance</param>
/// <param name="leftJoinIn">List of LeftJoins to be performed</param>
/// <param name="http">DTRequest Instance for where conditions</param>
/// <param name="fields">Array of all of the other fields</param>
/// <returns>List of SearchBuilderOptions</returns>
internal List<Dictionary<string, object>> Exec(Field fieldIn, Editor editor, List<LeftJoin> leftJoinIn, DtRequest http, Field[] fields)
{
var db = editor.Db();
string _label;
if(this._value == null){
this._value = fieldIn.DbField();
}
if(this._table == null){
var readTable = editor.ReadTable();
if(readTable.Count() == 0) {
this._table = editor.Table()[0].ToString();
}
else {
this._table = readTable[0];
}
}
if(this._label == null){
_label = this._value;
}
else {
_label = this._label.First();
}
// Just return the label if no default renderer
var formatter = _renderer ?? (str =>
{
return str;
});
if(leftJoinIn.Count() > 0){
this._leftJoin = leftJoinIn;
}
var query = db.Query("select")
.Table(this._table)
.LeftJoin(_leftJoin);
if(fieldIn.Apply("get") && fieldIn.GetValue() == null) {
query
.Get(this._value + " as value")
.Get(_label + " as label")
.GroupBy(this._value + ", " + _label);
}
var res = query.Exec()
.FetchAll();
// Replace labels from database with enum names, fall back on database values
if (_fromEnum.Count > 0) {
foreach (var row in res) {
row["label"] = _fromEnum[row["label"].ToString()] ?? row["label"].ToString();
}
}
// Create output object with all of the SearchBuilderOptions
List<Dictionary<string, object>> output = new List<Dictionary<string, object>>();
for (int i=0, ien=res.Count() ; i<ien ; i++ ) {
output.Add(new Dictionary<string, object>{
{"label", formatter(
(res[i]["label"] is DBNull) ? null : res[i]["label"].ToString()
)},
{"value", res[i]["value"] is DBNull ? null : res[i]["value"].ToString()}
});
}
if (_order == null)
{
string emptyStringa = "";
string emptyStringb = "";
output.Sort((a, b) => (a["label"] == null && b["label"] == null) ?
emptyStringa.CompareTo(emptyStringb) :
(a["label"] == null) ?
emptyStringa.CompareTo(b["label"].ToString()) :
(b["label"] == null) ?
a["label"].ToString().CompareTo(emptyStringb) :
a["label"].ToString().CompareTo(b["label"].ToString())
);
}
return output.ToList();
}
}
}