logger)
15 | {
16 | _logger = logger;
17 | }
18 |
19 | public IActionResult Index()
20 | {
21 | var jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
22 |
23 | var definitions = typeof(PersonRecord).GetDefaultColumnDefinitionsForType(false);
24 | var people = PersonBuilder.GetPeople();
25 |
26 | //Augment the definitions to show advanced scenarios not
27 | //handled by GetDefaultColumnDefinitionsForType(...)
28 |
29 | //Let's tweak the generated definition of FirstName to make it
30 | //a select element in jQuery QueryBuilder UI populated by
31 | //the possible values from our dataset
32 | var firstName = definitions.First(p => p.Field.ToLower() == "firstname");
33 | firstName.Values = people.Select(p => p.FirstName).Distinct().ToList();
34 | firstName.Input = "select";
35 |
36 | var birthday = definitions.First(p => p.Field.ToLower() == "birthday");
37 | birthday.Plugin = "datepicker";
38 | birthday.Plugin_config = new
39 | {
40 | format = "mm/dd/yyyy",
41 | todayBtn = "linked",
42 | todayHighlight = true,
43 | autoclose = true
44 | };
45 |
46 | ViewBag.FilterDefinition =
47 | JsonConvert.SerializeObject(definitions, jsonSerializerSettings);
48 | ViewBag.Model = people;
49 | return View();
50 | }
51 |
52 | [HttpPost]
53 | public JsonResult Index([FromBody]QueryBuilderFilterRule obj)
54 | {
55 | var people = PersonBuilder.GetPeople().BuildQuery(obj).ToList();
56 | return Json(people);
57 | }
58 |
59 |
60 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
61 | public IActionResult Error()
62 | {
63 | return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Models/ErrorViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace Castle.DynamicLinqQueryBuilder.Example.Models
2 | {
3 | public class ErrorViewModel
4 | {
5 | public string? RequestId { get; set; }
6 |
7 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
8 | }
9 | }
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Program.cs:
--------------------------------------------------------------------------------
1 | var builder = WebApplication.CreateBuilder(args);
2 |
3 | // Add services to the container.
4 | builder.Services.AddControllersWithViews();
5 |
6 | var app = builder.Build();
7 |
8 | // Configure the HTTP request pipeline.
9 | if (!app.Environment.IsDevelopment())
10 | {
11 | app.UseExceptionHandler("/Home/Error");
12 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
13 | app.UseHsts();
14 | }
15 |
16 | app.UseHttpsRedirection();
17 | app.UseStaticFiles();
18 |
19 | app.UseRouting();
20 |
21 | app.UseAuthorization();
22 |
23 | app.MapControllerRoute(
24 | name: "default",
25 | pattern: "{controller=Home}/{action=Index}/{id?}");
26 |
27 | app.Run();
28 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:63130",
7 | "sslPort": 44395
8 | }
9 | },
10 | "profiles": {
11 | "Castle.DynamicLinqQueryBuilder.Example": {
12 | "commandName": "Project",
13 | "dotnetRunMessages": true,
14 | "launchBrowser": true,
15 | "applicationUrl": "https://localhost:7288;http://localhost:5288",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "IIS Express": {
21 | "commandName": "IISExpress",
22 | "launchBrowser": true,
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Sample/PersonRecord.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Castle.DynamicLinqQueryBuilder.Example.Sample
4 | {
5 | public class PersonRecord
6 | {
7 | public string FirstName { get; set; }
8 | public string LastName { get; set; }
9 | public DateTime Birthday { get; set; }
10 | public string Address { get; set; }
11 | public string City { get; set; }
12 | public string State { get; set; }
13 | public string ZipCode { get; set; }
14 | public bool Deceased { get; set; }
15 |
16 | }
17 | }
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Home Page";
3 | }
4 | @section scripts
5 | {
6 |
115 | }
116 |
117 |
Dynamic Linq Query Builder Example
118 |
Dynamically filter object collections based on complex queries at runtime.
119 |
120 |
121 |
122 |
123 |
Build Filters
124 |
125 |
Apply Filter
126 |
127 |
128 |
User Data
129 |
130 |
131 |
132 | First Name
133 | Last Name
134 | Birthday
135 | Deceased
136 | Address
137 | City
138 | State
139 | Zip Code
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 | @model ErrorViewModel
2 | @{
3 | ViewData["Title"] = "Error";
4 | }
5 |
6 | Error.
7 | An error occurred while processing your request.
8 |
9 | @if (Model.ShowRequestId)
10 | {
11 |
12 | Request ID: @Model.RequestId
13 |
14 | }
15 |
16 | Development Mode
17 |
18 | Swapping to Development environment will display more detailed information about the error that occurred.
19 |
20 |
21 | The Development environment shouldn't be enabled for deployed applications.
22 | It can result in displaying sensitive information from exceptions to end users.
23 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
24 | and restarting the app.
25 |
26 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - Castle.DynamicLinqQueryBuilder.Example
7 |
8 |
9 |
10 |
11 |
12 |
30 |
31 |
32 | @RenderBody()
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 | @await RenderSectionAsync("Scripts", required: false)
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/Shared/_Layout.cshtml.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | a {
11 | color: #0077cc;
12 | }
13 |
14 | .btn-primary {
15 | color: #fff;
16 | background-color: #1b6ec2;
17 | border-color: #1861ac;
18 | }
19 |
20 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
21 | color: #fff;
22 | background-color: #1b6ec2;
23 | border-color: #1861ac;
24 | }
25 |
26 | .border-top {
27 | border-top: 1px solid #e5e5e5;
28 | }
29 | .border-bottom {
30 | border-bottom: 1px solid #e5e5e5;
31 | }
32 |
33 | .box-shadow {
34 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
35 | }
36 |
37 | button.accept-policy {
38 | font-size: 1rem;
39 | line-height: inherit;
40 | }
41 |
42 | .footer {
43 | position: absolute;
44 | bottom: 0;
45 | width: 100%;
46 | white-space: nowrap;
47 | line-height: 60px;
48 | }
49 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using Castle.DynamicLinqQueryBuilder.Example
2 | @using Castle.DynamicLinqQueryBuilder.Example.Models
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/css/query-builder.default.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery QueryBuilder 2.3.2
3 | * Copyright 2014-2016 Damien "Mistic" Sorel (http://www.strangeplanet.fr)
4 | * Licensed under MIT (http://opensource.org/licenses/MIT)
5 | */
6 |
7 | .query-builder .rule-container,.query-builder .rule-placeholder,.query-builder .rules-group-container{position:relative;margin:4px 0;border-radius:5px;padding:5px;border:1px solid #EEE;background:rgba(255,255,255,.9)}.query-builder .drag-handle,.query-builder .error-container,.query-builder .rule-container .rule-filter-container,.query-builder .rule-container .rule-operator-container,.query-builder .rule-container .rule-value-container{display:inline-block;margin:0 5px 0 0;vertical-align:middle}.query-builder .rules-group-container{padding:10px 10px 6px;border:1px solid #DCC896;background:rgba(250,240,210,.5)}.query-builder .rules-group-header{margin-bottom:10px}.query-builder .rules-group-header .group-conditions .btn.disabled:not(.active),.query-builder .rules-group-header .group-conditions input[name$=_cond]{display:none}.query-builder .rules-group-header .group-conditions .btn.disabled{border-radius:3px}.query-builder .rules-list{list-style:none;padding:0 0 0 15px;margin:0}.query-builder .rule-value-container{border-left:1px solid #DDD;padding-left:5px}.query-builder .rule-value-container label{margin-bottom:0;font-weight:400}.query-builder .rule-value-container label.block{display:block}.query-builder .rule-value-container input[type=number],.query-builder .rule-value-container input[type=text],.query-builder .rule-value-container select{padding:1px}.query-builder .error-container{display:none;cursor:help;color:red}.query-builder .has-error{background-color:#FDD;border-color:#F99}.query-builder .has-error .error-container{display:inline-block!important}.query-builder .rules-list>::after,.query-builder .rules-list>::before{content:'';position:absolute;left:-10px;width:10px;height:calc(50% + 4px);border-color:#CCC;border-style:solid}.query-builder .rules-list>::before{top:-4px;border-width:0 0 2px 2px}.query-builder .rules-list>::after{top:50%;border-width:0 0 0 2px}.query-builder .rules-list>:first-child::before{top:-12px;height:calc(50% + 14px)}.query-builder .rules-list>:last-child::before{border-radius:0 0 0 4px}.query-builder .rules-list>:last-child::after{display:none}.query-builder .error-container+.tooltip .tooltip-inner{color:#F99!important}.query-builder .filter-description{margin:5px 0 0;background:#D9EDF7;border:1px solid #BCE8F1;color:#31708F;border-radius:5px;padding:2.5px 5px;font-size:.8em}.query-builder .rules-group-header [data-invert]{margin-left:5px}.query-builder .drag-handle{cursor:move;vertical-align:middle;margin-left:5px}.query-builder .dragged{opacity:.5}.query-builder .rule-placeholder{border:1px dashed #BBB;opacity:.7}
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | html {
2 | font-size: 14px;
3 | }
4 |
5 | @media (min-width: 768px) {
6 | html {
7 | font-size: 16px;
8 | }
9 | }
10 |
11 | html {
12 | position: relative;
13 | min-height: 100%;
14 | }
15 |
16 | body {
17 | margin-bottom: 60px;
18 | }
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tghamm/dynamic-linq-query-builder/b5281fe48e1ffa584f650270b464c1d1e611c865/Castle.DynamicLinqQueryBuilder.Example/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your JavaScript code.
5 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2021 Twitter, Inc.
4 | Copyright (c) 2011-2021 The Bootstrap Authors
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | @media (prefers-reduced-motion: no-preference) {
15 | :root {
16 | scroll-behavior: smooth;
17 | }
18 | }
19 |
20 | body {
21 | margin: 0;
22 | font-family: var(--bs-body-font-family);
23 | font-size: var(--bs-body-font-size);
24 | font-weight: var(--bs-body-font-weight);
25 | line-height: var(--bs-body-line-height);
26 | color: var(--bs-body-color);
27 | text-align: var(--bs-body-text-align);
28 | background-color: var(--bs-body-bg);
29 | -webkit-text-size-adjust: 100%;
30 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
31 | }
32 |
33 | hr {
34 | margin: 1rem 0;
35 | color: inherit;
36 | background-color: currentColor;
37 | border: 0;
38 | opacity: 0.25;
39 | }
40 |
41 | hr:not([size]) {
42 | height: 1px;
43 | }
44 |
45 | h6, h5, h4, h3, h2, h1 {
46 | margin-top: 0;
47 | margin-bottom: 0.5rem;
48 | font-weight: 500;
49 | line-height: 1.2;
50 | }
51 |
52 | h1 {
53 | font-size: calc(1.375rem + 1.5vw);
54 | }
55 | @media (min-width: 1200px) {
56 | h1 {
57 | font-size: 2.5rem;
58 | }
59 | }
60 |
61 | h2 {
62 | font-size: calc(1.325rem + 0.9vw);
63 | }
64 | @media (min-width: 1200px) {
65 | h2 {
66 | font-size: 2rem;
67 | }
68 | }
69 |
70 | h3 {
71 | font-size: calc(1.3rem + 0.6vw);
72 | }
73 | @media (min-width: 1200px) {
74 | h3 {
75 | font-size: 1.75rem;
76 | }
77 | }
78 |
79 | h4 {
80 | font-size: calc(1.275rem + 0.3vw);
81 | }
82 | @media (min-width: 1200px) {
83 | h4 {
84 | font-size: 1.5rem;
85 | }
86 | }
87 |
88 | h5 {
89 | font-size: 1.25rem;
90 | }
91 |
92 | h6 {
93 | font-size: 1rem;
94 | }
95 |
96 | p {
97 | margin-top: 0;
98 | margin-bottom: 1rem;
99 | }
100 |
101 | abbr[title],
102 | abbr[data-bs-original-title] {
103 | -webkit-text-decoration: underline dotted;
104 | text-decoration: underline dotted;
105 | cursor: help;
106 | -webkit-text-decoration-skip-ink: none;
107 | text-decoration-skip-ink: none;
108 | }
109 |
110 | address {
111 | margin-bottom: 1rem;
112 | font-style: normal;
113 | line-height: inherit;
114 | }
115 |
116 | ol,
117 | ul {
118 | padding-left: 2rem;
119 | }
120 |
121 | ol,
122 | ul,
123 | dl {
124 | margin-top: 0;
125 | margin-bottom: 1rem;
126 | }
127 |
128 | ol ol,
129 | ul ul,
130 | ol ul,
131 | ul ol {
132 | margin-bottom: 0;
133 | }
134 |
135 | dt {
136 | font-weight: 700;
137 | }
138 |
139 | dd {
140 | margin-bottom: 0.5rem;
141 | margin-left: 0;
142 | }
143 |
144 | blockquote {
145 | margin: 0 0 1rem;
146 | }
147 |
148 | b,
149 | strong {
150 | font-weight: bolder;
151 | }
152 |
153 | small {
154 | font-size: 0.875em;
155 | }
156 |
157 | mark {
158 | padding: 0.2em;
159 | background-color: #fcf8e3;
160 | }
161 |
162 | sub,
163 | sup {
164 | position: relative;
165 | font-size: 0.75em;
166 | line-height: 0;
167 | vertical-align: baseline;
168 | }
169 |
170 | sub {
171 | bottom: -0.25em;
172 | }
173 |
174 | sup {
175 | top: -0.5em;
176 | }
177 |
178 | a {
179 | color: #0d6efd;
180 | text-decoration: underline;
181 | }
182 | a:hover {
183 | color: #0a58ca;
184 | }
185 |
186 | a:not([href]):not([class]), a:not([href]):not([class]):hover {
187 | color: inherit;
188 | text-decoration: none;
189 | }
190 |
191 | pre,
192 | code,
193 | kbd,
194 | samp {
195 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
196 | font-size: 1em;
197 | direction: ltr /* rtl:ignore */;
198 | unicode-bidi: bidi-override;
199 | }
200 |
201 | pre {
202 | display: block;
203 | margin-top: 0;
204 | margin-bottom: 1rem;
205 | overflow: auto;
206 | font-size: 0.875em;
207 | }
208 | pre code {
209 | font-size: inherit;
210 | color: inherit;
211 | word-break: normal;
212 | }
213 |
214 | code {
215 | font-size: 0.875em;
216 | color: #d63384;
217 | word-wrap: break-word;
218 | }
219 | a > code {
220 | color: inherit;
221 | }
222 |
223 | kbd {
224 | padding: 0.2rem 0.4rem;
225 | font-size: 0.875em;
226 | color: #fff;
227 | background-color: #212529;
228 | border-radius: 0.2rem;
229 | }
230 | kbd kbd {
231 | padding: 0;
232 | font-size: 1em;
233 | font-weight: 700;
234 | }
235 |
236 | figure {
237 | margin: 0 0 1rem;
238 | }
239 |
240 | img,
241 | svg {
242 | vertical-align: middle;
243 | }
244 |
245 | table {
246 | caption-side: bottom;
247 | border-collapse: collapse;
248 | }
249 |
250 | caption {
251 | padding-top: 0.5rem;
252 | padding-bottom: 0.5rem;
253 | color: #6c757d;
254 | text-align: left;
255 | }
256 |
257 | th {
258 | text-align: inherit;
259 | text-align: -webkit-match-parent;
260 | }
261 |
262 | thead,
263 | tbody,
264 | tfoot,
265 | tr,
266 | td,
267 | th {
268 | border-color: inherit;
269 | border-style: solid;
270 | border-width: 0;
271 | }
272 |
273 | label {
274 | display: inline-block;
275 | }
276 |
277 | button {
278 | border-radius: 0;
279 | }
280 |
281 | button:focus:not(:focus-visible) {
282 | outline: 0;
283 | }
284 |
285 | input,
286 | button,
287 | select,
288 | optgroup,
289 | textarea {
290 | margin: 0;
291 | font-family: inherit;
292 | font-size: inherit;
293 | line-height: inherit;
294 | }
295 |
296 | button,
297 | select {
298 | text-transform: none;
299 | }
300 |
301 | [role=button] {
302 | cursor: pointer;
303 | }
304 |
305 | select {
306 | word-wrap: normal;
307 | }
308 | select:disabled {
309 | opacity: 1;
310 | }
311 |
312 | [list]::-webkit-calendar-picker-indicator {
313 | display: none;
314 | }
315 |
316 | button,
317 | [type=button],
318 | [type=reset],
319 | [type=submit] {
320 | -webkit-appearance: button;
321 | }
322 | button:not(:disabled),
323 | [type=button]:not(:disabled),
324 | [type=reset]:not(:disabled),
325 | [type=submit]:not(:disabled) {
326 | cursor: pointer;
327 | }
328 |
329 | ::-moz-focus-inner {
330 | padding: 0;
331 | border-style: none;
332 | }
333 |
334 | textarea {
335 | resize: vertical;
336 | }
337 |
338 | fieldset {
339 | min-width: 0;
340 | padding: 0;
341 | margin: 0;
342 | border: 0;
343 | }
344 |
345 | legend {
346 | float: left;
347 | width: 100%;
348 | padding: 0;
349 | margin-bottom: 0.5rem;
350 | font-size: calc(1.275rem + 0.3vw);
351 | line-height: inherit;
352 | }
353 | @media (min-width: 1200px) {
354 | legend {
355 | font-size: 1.5rem;
356 | }
357 | }
358 | legend + * {
359 | clear: left;
360 | }
361 |
362 | ::-webkit-datetime-edit-fields-wrapper,
363 | ::-webkit-datetime-edit-text,
364 | ::-webkit-datetime-edit-minute,
365 | ::-webkit-datetime-edit-hour-field,
366 | ::-webkit-datetime-edit-day-field,
367 | ::-webkit-datetime-edit-month-field,
368 | ::-webkit-datetime-edit-year-field {
369 | padding: 0;
370 | }
371 |
372 | ::-webkit-inner-spin-button {
373 | height: auto;
374 | }
375 |
376 | [type=search] {
377 | outline-offset: -2px;
378 | -webkit-appearance: textfield;
379 | }
380 |
381 | /* rtl:raw:
382 | [type="tel"],
383 | [type="url"],
384 | [type="email"],
385 | [type="number"] {
386 | direction: ltr;
387 | }
388 | */
389 | ::-webkit-search-decoration {
390 | -webkit-appearance: none;
391 | }
392 |
393 | ::-webkit-color-swatch-wrapper {
394 | padding: 0;
395 | }
396 |
397 | ::file-selector-button {
398 | font: inherit;
399 | }
400 |
401 | ::-webkit-file-upload-button {
402 | font: inherit;
403 | -webkit-appearance: button;
404 | }
405 |
406 | output {
407 | display: inline-block;
408 | }
409 |
410 | iframe {
411 | border: 0;
412 | }
413 |
414 | summary {
415 | display: list-item;
416 | cursor: pointer;
417 | }
418 |
419 | progress {
420 | vertical-align: baseline;
421 | }
422 |
423 | [hidden] {
424 | display: none !important;
425 | }
426 |
427 | /*# sourceMappingURL=bootstrap-reboot.css.map */
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */
8 | *,
9 | *::before,
10 | *::after {
11 | box-sizing: border-box;
12 | }
13 |
14 | @media (prefers-reduced-motion: no-preference) {
15 | :root {
16 | scroll-behavior: smooth;
17 | }
18 | }
19 |
20 | body {
21 | margin: 0;
22 | font-family: var(--bs-body-font-family);
23 | font-size: var(--bs-body-font-size);
24 | font-weight: var(--bs-body-font-weight);
25 | line-height: var(--bs-body-line-height);
26 | color: var(--bs-body-color);
27 | text-align: var(--bs-body-text-align);
28 | background-color: var(--bs-body-bg);
29 | -webkit-text-size-adjust: 100%;
30 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
31 | }
32 |
33 | hr {
34 | margin: 1rem 0;
35 | color: inherit;
36 | background-color: currentColor;
37 | border: 0;
38 | opacity: 0.25;
39 | }
40 |
41 | hr:not([size]) {
42 | height: 1px;
43 | }
44 |
45 | h6, h5, h4, h3, h2, h1 {
46 | margin-top: 0;
47 | margin-bottom: 0.5rem;
48 | font-weight: 500;
49 | line-height: 1.2;
50 | }
51 |
52 | h1 {
53 | font-size: calc(1.375rem + 1.5vw);
54 | }
55 | @media (min-width: 1200px) {
56 | h1 {
57 | font-size: 2.5rem;
58 | }
59 | }
60 |
61 | h2 {
62 | font-size: calc(1.325rem + 0.9vw);
63 | }
64 | @media (min-width: 1200px) {
65 | h2 {
66 | font-size: 2rem;
67 | }
68 | }
69 |
70 | h3 {
71 | font-size: calc(1.3rem + 0.6vw);
72 | }
73 | @media (min-width: 1200px) {
74 | h3 {
75 | font-size: 1.75rem;
76 | }
77 | }
78 |
79 | h4 {
80 | font-size: calc(1.275rem + 0.3vw);
81 | }
82 | @media (min-width: 1200px) {
83 | h4 {
84 | font-size: 1.5rem;
85 | }
86 | }
87 |
88 | h5 {
89 | font-size: 1.25rem;
90 | }
91 |
92 | h6 {
93 | font-size: 1rem;
94 | }
95 |
96 | p {
97 | margin-top: 0;
98 | margin-bottom: 1rem;
99 | }
100 |
101 | abbr[title],
102 | abbr[data-bs-original-title] {
103 | -webkit-text-decoration: underline dotted;
104 | text-decoration: underline dotted;
105 | cursor: help;
106 | -webkit-text-decoration-skip-ink: none;
107 | text-decoration-skip-ink: none;
108 | }
109 |
110 | address {
111 | margin-bottom: 1rem;
112 | font-style: normal;
113 | line-height: inherit;
114 | }
115 |
116 | ol,
117 | ul {
118 | padding-right: 2rem;
119 | }
120 |
121 | ol,
122 | ul,
123 | dl {
124 | margin-top: 0;
125 | margin-bottom: 1rem;
126 | }
127 |
128 | ol ol,
129 | ul ul,
130 | ol ul,
131 | ul ol {
132 | margin-bottom: 0;
133 | }
134 |
135 | dt {
136 | font-weight: 700;
137 | }
138 |
139 | dd {
140 | margin-bottom: 0.5rem;
141 | margin-right: 0;
142 | }
143 |
144 | blockquote {
145 | margin: 0 0 1rem;
146 | }
147 |
148 | b,
149 | strong {
150 | font-weight: bolder;
151 | }
152 |
153 | small {
154 | font-size: 0.875em;
155 | }
156 |
157 | mark {
158 | padding: 0.2em;
159 | background-color: #fcf8e3;
160 | }
161 |
162 | sub,
163 | sup {
164 | position: relative;
165 | font-size: 0.75em;
166 | line-height: 0;
167 | vertical-align: baseline;
168 | }
169 |
170 | sub {
171 | bottom: -0.25em;
172 | }
173 |
174 | sup {
175 | top: -0.5em;
176 | }
177 |
178 | a {
179 | color: #0d6efd;
180 | text-decoration: underline;
181 | }
182 | a:hover {
183 | color: #0a58ca;
184 | }
185 |
186 | a:not([href]):not([class]), a:not([href]):not([class]):hover {
187 | color: inherit;
188 | text-decoration: none;
189 | }
190 |
191 | pre,
192 | code,
193 | kbd,
194 | samp {
195 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
196 | font-size: 1em;
197 | direction: ltr ;
198 | unicode-bidi: bidi-override;
199 | }
200 |
201 | pre {
202 | display: block;
203 | margin-top: 0;
204 | margin-bottom: 1rem;
205 | overflow: auto;
206 | font-size: 0.875em;
207 | }
208 | pre code {
209 | font-size: inherit;
210 | color: inherit;
211 | word-break: normal;
212 | }
213 |
214 | code {
215 | font-size: 0.875em;
216 | color: #d63384;
217 | word-wrap: break-word;
218 | }
219 | a > code {
220 | color: inherit;
221 | }
222 |
223 | kbd {
224 | padding: 0.2rem 0.4rem;
225 | font-size: 0.875em;
226 | color: #fff;
227 | background-color: #212529;
228 | border-radius: 0.2rem;
229 | }
230 | kbd kbd {
231 | padding: 0;
232 | font-size: 1em;
233 | font-weight: 700;
234 | }
235 |
236 | figure {
237 | margin: 0 0 1rem;
238 | }
239 |
240 | img,
241 | svg {
242 | vertical-align: middle;
243 | }
244 |
245 | table {
246 | caption-side: bottom;
247 | border-collapse: collapse;
248 | }
249 |
250 | caption {
251 | padding-top: 0.5rem;
252 | padding-bottom: 0.5rem;
253 | color: #6c757d;
254 | text-align: right;
255 | }
256 |
257 | th {
258 | text-align: inherit;
259 | text-align: -webkit-match-parent;
260 | }
261 |
262 | thead,
263 | tbody,
264 | tfoot,
265 | tr,
266 | td,
267 | th {
268 | border-color: inherit;
269 | border-style: solid;
270 | border-width: 0;
271 | }
272 |
273 | label {
274 | display: inline-block;
275 | }
276 |
277 | button {
278 | border-radius: 0;
279 | }
280 |
281 | button:focus:not(:focus-visible) {
282 | outline: 0;
283 | }
284 |
285 | input,
286 | button,
287 | select,
288 | optgroup,
289 | textarea {
290 | margin: 0;
291 | font-family: inherit;
292 | font-size: inherit;
293 | line-height: inherit;
294 | }
295 |
296 | button,
297 | select {
298 | text-transform: none;
299 | }
300 |
301 | [role=button] {
302 | cursor: pointer;
303 | }
304 |
305 | select {
306 | word-wrap: normal;
307 | }
308 | select:disabled {
309 | opacity: 1;
310 | }
311 |
312 | [list]::-webkit-calendar-picker-indicator {
313 | display: none;
314 | }
315 |
316 | button,
317 | [type=button],
318 | [type=reset],
319 | [type=submit] {
320 | -webkit-appearance: button;
321 | }
322 | button:not(:disabled),
323 | [type=button]:not(:disabled),
324 | [type=reset]:not(:disabled),
325 | [type=submit]:not(:disabled) {
326 | cursor: pointer;
327 | }
328 |
329 | ::-moz-focus-inner {
330 | padding: 0;
331 | border-style: none;
332 | }
333 |
334 | textarea {
335 | resize: vertical;
336 | }
337 |
338 | fieldset {
339 | min-width: 0;
340 | padding: 0;
341 | margin: 0;
342 | border: 0;
343 | }
344 |
345 | legend {
346 | float: right;
347 | width: 100%;
348 | padding: 0;
349 | margin-bottom: 0.5rem;
350 | font-size: calc(1.275rem + 0.3vw);
351 | line-height: inherit;
352 | }
353 | @media (min-width: 1200px) {
354 | legend {
355 | font-size: 1.5rem;
356 | }
357 | }
358 | legend + * {
359 | clear: right;
360 | }
361 |
362 | ::-webkit-datetime-edit-fields-wrapper,
363 | ::-webkit-datetime-edit-text,
364 | ::-webkit-datetime-edit-minute,
365 | ::-webkit-datetime-edit-hour-field,
366 | ::-webkit-datetime-edit-day-field,
367 | ::-webkit-datetime-edit-month-field,
368 | ::-webkit-datetime-edit-year-field {
369 | padding: 0;
370 | }
371 |
372 | ::-webkit-inner-spin-button {
373 | height: auto;
374 | }
375 |
376 | [type=search] {
377 | outline-offset: -2px;
378 | -webkit-appearance: textfield;
379 | }
380 |
381 | [type="tel"],
382 | [type="url"],
383 | [type="email"],
384 | [type="number"] {
385 | direction: ltr;
386 | }
387 | ::-webkit-search-decoration {
388 | -webkit-appearance: none;
389 | }
390 |
391 | ::-webkit-color-swatch-wrapper {
392 | padding: 0;
393 | }
394 |
395 | ::file-selector-button {
396 | font: inherit;
397 | }
398 |
399 | ::-webkit-file-upload-button {
400 | font: inherit;
401 | -webkit-appearance: button;
402 | }
403 |
404 | output {
405 | display: inline-block;
406 | }
407 |
408 | iframe {
409 | border: 0;
410 | }
411 |
412 | summary {
413 | display: list-item;
414 | cursor: pointer;
415 | }
416 |
417 | progress {
418 | vertical-align: baseline;
419 | }
420 |
421 | [hidden] {
422 | display: none !important;
423 | }
424 | /*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
3 | * Copyright 2011-2021 The Bootstrap Authors
4 | * Copyright 2011-2021 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) .NET Foundation. All rights reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | these files except in compliance with the License. You may obtain a copy of the
5 | License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software distributed
10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the
12 | specific language governing permissions and limitations under the License.
13 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js:
--------------------------------------------------------------------------------
1 | // Unobtrusive validation support library for jQuery and jQuery Validate
2 | // Copyright (c) .NET Foundation. All rights reserved.
3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
4 | // @version v3.2.11
5 |
6 | /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
7 | /*global document: false, jQuery: false */
8 |
9 | (function (factory) {
10 | if (typeof define === 'function' && define.amd) {
11 | // AMD. Register as an anonymous module.
12 | define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
13 | } else if (typeof module === 'object' && module.exports) {
14 | // CommonJS-like environments that support module.exports
15 | module.exports = factory(require('jquery-validation'));
16 | } else {
17 | // Browser global
18 | jQuery.validator.unobtrusive = factory(jQuery);
19 | }
20 | }(function ($) {
21 | var $jQval = $.validator,
22 | adapters,
23 | data_validation = "unobtrusiveValidation";
24 |
25 | function setValidationValues(options, ruleName, value) {
26 | options.rules[ruleName] = value;
27 | if (options.message) {
28 | options.messages[ruleName] = options.message;
29 | }
30 | }
31 |
32 | function splitAndTrim(value) {
33 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
34 | }
35 |
36 | function escapeAttributeValue(value) {
37 | // As mentioned on http://api.jquery.com/category/selectors/
38 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
39 | }
40 |
41 | function getModelPrefix(fieldName) {
42 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
43 | }
44 |
45 | function appendModelPrefix(value, prefix) {
46 | if (value.indexOf("*.") === 0) {
47 | value = value.replace("*.", prefix);
48 | }
49 | return value;
50 | }
51 |
52 | function onError(error, inputElement) { // 'this' is the form element
53 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
54 | replaceAttrValue = container.attr("data-valmsg-replace"),
55 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
56 |
57 | container.removeClass("field-validation-valid").addClass("field-validation-error");
58 | error.data("unobtrusiveContainer", container);
59 |
60 | if (replace) {
61 | container.empty();
62 | error.removeClass("input-validation-error").appendTo(container);
63 | }
64 | else {
65 | error.hide();
66 | }
67 | }
68 |
69 | function onErrors(event, validator) { // 'this' is the form element
70 | var container = $(this).find("[data-valmsg-summary=true]"),
71 | list = container.find("ul");
72 |
73 | if (list && list.length && validator.errorList.length) {
74 | list.empty();
75 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
76 |
77 | $.each(validator.errorList, function () {
78 | $(" ").html(this.message).appendTo(list);
79 | });
80 | }
81 | }
82 |
83 | function onSuccess(error) { // 'this' is the form element
84 | var container = error.data("unobtrusiveContainer");
85 |
86 | if (container) {
87 | var replaceAttrValue = container.attr("data-valmsg-replace"),
88 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
89 |
90 | container.addClass("field-validation-valid").removeClass("field-validation-error");
91 | error.removeData("unobtrusiveContainer");
92 |
93 | if (replace) {
94 | container.empty();
95 | }
96 | }
97 | }
98 |
99 | function onReset(event) { // 'this' is the form element
100 | var $form = $(this),
101 | key = '__jquery_unobtrusive_validation_form_reset';
102 | if ($form.data(key)) {
103 | return;
104 | }
105 | // Set a flag that indicates we're currently resetting the form.
106 | $form.data(key, true);
107 | try {
108 | $form.data("validator").resetForm();
109 | } finally {
110 | $form.removeData(key);
111 | }
112 |
113 | $form.find(".validation-summary-errors")
114 | .addClass("validation-summary-valid")
115 | .removeClass("validation-summary-errors");
116 | $form.find(".field-validation-error")
117 | .addClass("field-validation-valid")
118 | .removeClass("field-validation-error")
119 | .removeData("unobtrusiveContainer")
120 | .find(">*") // If we were using valmsg-replace, get the underlying error
121 | .removeData("unobtrusiveContainer");
122 | }
123 |
124 | function validationInfo(form) {
125 | var $form = $(form),
126 | result = $form.data(data_validation),
127 | onResetProxy = $.proxy(onReset, form),
128 | defaultOptions = $jQval.unobtrusive.options || {},
129 | execInContext = function (name, args) {
130 | var func = defaultOptions[name];
131 | func && $.isFunction(func) && func.apply(form, args);
132 | };
133 |
134 | if (!result) {
135 | result = {
136 | options: { // options structure passed to jQuery Validate's validate() method
137 | errorClass: defaultOptions.errorClass || "input-validation-error",
138 | errorElement: defaultOptions.errorElement || "span",
139 | errorPlacement: function () {
140 | onError.apply(form, arguments);
141 | execInContext("errorPlacement", arguments);
142 | },
143 | invalidHandler: function () {
144 | onErrors.apply(form, arguments);
145 | execInContext("invalidHandler", arguments);
146 | },
147 | messages: {},
148 | rules: {},
149 | success: function () {
150 | onSuccess.apply(form, arguments);
151 | execInContext("success", arguments);
152 | }
153 | },
154 | attachValidation: function () {
155 | $form
156 | .off("reset." + data_validation, onResetProxy)
157 | .on("reset." + data_validation, onResetProxy)
158 | .validate(this.options);
159 | },
160 | validate: function () { // a validation function that is called by unobtrusive Ajax
161 | $form.validate();
162 | return $form.valid();
163 | }
164 | };
165 | $form.data(data_validation, result);
166 | }
167 |
168 | return result;
169 | }
170 |
171 | $jQval.unobtrusive = {
172 | adapters: [],
173 |
174 | parseElement: function (element, skipAttach) {
175 | ///
176 | /// Parses a single HTML element for unobtrusive validation attributes.
177 | ///
178 | /// The HTML element to be parsed.
179 | /// [Optional] true to skip attaching the
180 | /// validation to the form. If parsing just this single element, you should specify true.
181 | /// If parsing several elements, you should specify false, and manually attach the validation
182 | /// to the form when you are finished. The default is false.
183 | var $element = $(element),
184 | form = $element.parents("form")[0],
185 | valInfo, rules, messages;
186 |
187 | if (!form) { // Cannot do client-side validation without a form
188 | return;
189 | }
190 |
191 | valInfo = validationInfo(form);
192 | valInfo.options.rules[element.name] = rules = {};
193 | valInfo.options.messages[element.name] = messages = {};
194 |
195 | $.each(this.adapters, function () {
196 | var prefix = "data-val-" + this.name,
197 | message = $element.attr(prefix),
198 | paramValues = {};
199 |
200 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
201 | prefix += "-";
202 |
203 | $.each(this.params, function () {
204 | paramValues[this] = $element.attr(prefix + this);
205 | });
206 |
207 | this.adapt({
208 | element: element,
209 | form: form,
210 | message: message,
211 | params: paramValues,
212 | rules: rules,
213 | messages: messages
214 | });
215 | }
216 | });
217 |
218 | $.extend(rules, { "__dummy__": true });
219 |
220 | if (!skipAttach) {
221 | valInfo.attachValidation();
222 | }
223 | },
224 |
225 | parse: function (selector) {
226 | ///
227 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
228 | /// with the [data-val=true] attribute value and enables validation according to the data-val-*
229 | /// attribute values.
230 | ///
231 | /// Any valid jQuery selector.
232 |
233 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
234 | // element with data-val=true
235 | var $selector = $(selector),
236 | $forms = $selector.parents()
237 | .addBack()
238 | .filter("form")
239 | .add($selector.find("form"))
240 | .has("[data-val=true]");
241 |
242 | $selector.find("[data-val=true]").each(function () {
243 | $jQval.unobtrusive.parseElement(this, true);
244 | });
245 |
246 | $forms.each(function () {
247 | var info = validationInfo(this);
248 | if (info) {
249 | info.attachValidation();
250 | }
251 | });
252 | }
253 | };
254 |
255 | adapters = $jQval.unobtrusive.adapters;
256 |
257 | adapters.add = function (adapterName, params, fn) {
258 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.
259 | /// The name of the adapter to be added. This matches the name used
260 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
261 | /// [Optional] An array of parameter names (strings) that will
262 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
263 | /// mmmm is the parameter name).
264 | /// The function to call, which adapts the values from the HTML
265 | /// attributes into jQuery Validate rules and/or messages.
266 | ///
267 | if (!fn) { // Called with no params, just a function
268 | fn = params;
269 | params = [];
270 | }
271 | this.push({ name: adapterName, params: params, adapt: fn });
272 | return this;
273 | };
274 |
275 | adapters.addBool = function (adapterName, ruleName) {
276 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
277 | /// the jQuery Validate validation rule has no parameter values.
278 | /// The name of the adapter to be added. This matches the name used
279 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
280 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
281 | /// of adapterName will be used instead.
282 | ///
283 | return this.add(adapterName, function (options) {
284 | setValidationValues(options, ruleName || adapterName, true);
285 | });
286 | };
287 |
288 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
289 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
290 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
291 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max.
292 | /// The name of the adapter to be added. This matches the name used
293 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
294 | /// The name of the jQuery Validate rule to be used when you only
295 | /// have a minimum value.
296 | /// The name of the jQuery Validate rule to be used when you only
297 | /// have a maximum value.
298 | /// The name of the jQuery Validate rule to be used when you
299 | /// have both a minimum and maximum value.
300 | /// [Optional] The name of the HTML attribute that
301 | /// contains the minimum value. The default is "min".
302 | /// [Optional] The name of the HTML attribute that
303 | /// contains the maximum value. The default is "max".
304 | ///
305 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
306 | var min = options.params.min,
307 | max = options.params.max;
308 |
309 | if (min && max) {
310 | setValidationValues(options, minMaxRuleName, [min, max]);
311 | }
312 | else if (min) {
313 | setValidationValues(options, minRuleName, min);
314 | }
315 | else if (max) {
316 | setValidationValues(options, maxRuleName, max);
317 | }
318 | });
319 | };
320 |
321 | adapters.addSingleVal = function (adapterName, attribute, ruleName) {
322 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
323 | /// the jQuery Validate validation rule has a single value.
324 | /// The name of the adapter to be added. This matches the name used
325 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).
326 | /// [Optional] The name of the HTML attribute that contains the value.
327 | /// The default is "val".
328 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
329 | /// of adapterName will be used instead.
330 | ///
331 | return this.add(adapterName, [attribute || "val"], function (options) {
332 | setValidationValues(options, ruleName || adapterName, options.params[attribute]);
333 | });
334 | };
335 |
336 | $jQval.addMethod("__dummy__", function (value, element, params) {
337 | return true;
338 | });
339 |
340 | $jQval.addMethod("regex", function (value, element, params) {
341 | var match;
342 | if (this.optional(element)) {
343 | return true;
344 | }
345 |
346 | match = new RegExp(params).exec(value);
347 | return (match && (match.index === 0) && (match[0].length === value.length));
348 | });
349 |
350 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
351 | var match;
352 | if (nonalphamin) {
353 | match = value.match(/\W/g);
354 | match = match && match.length >= nonalphamin;
355 | }
356 | return match;
357 | });
358 |
359 | if ($jQval.methods.extension) {
360 | adapters.addSingleVal("accept", "mimtype");
361 | adapters.addSingleVal("extension", "extension");
362 | } else {
363 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
364 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
365 | // validating the extension, and ignore mime-type validations as they are not supported.
366 | adapters.addSingleVal("extension", "extension", "accept");
367 | }
368 |
369 | adapters.addSingleVal("regex", "pattern");
370 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
371 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
372 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
373 | adapters.add("equalto", ["other"], function (options) {
374 | var prefix = getModelPrefix(options.element.name),
375 | other = options.params.other,
376 | fullOtherName = appendModelPrefix(other, prefix),
377 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
378 |
379 | setValidationValues(options, "equalTo", element);
380 | });
381 | adapters.add("required", function (options) {
382 | // jQuery Validate equates "required" with "mandatory" for checkbox elements
383 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
384 | setValidationValues(options, "required", true);
385 | }
386 | });
387 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
388 | var value = {
389 | url: options.params.url,
390 | type: options.params.type || "GET",
391 | data: {}
392 | },
393 | prefix = getModelPrefix(options.element.name);
394 |
395 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
396 | var paramName = appendModelPrefix(fieldName, prefix);
397 | value.data[paramName] = function () {
398 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
399 | // For checkboxes and radio buttons, only pick up values from checked fields.
400 | if (field.is(":checkbox")) {
401 | return field.filter(":checked").val() || field.filter(":hidden").val() || '';
402 | }
403 | else if (field.is(":radio")) {
404 | return field.filter(":checked").val() || '';
405 | }
406 | return field.val();
407 | };
408 | });
409 |
410 | setValidationValues(options, "remote", value);
411 | });
412 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
413 | if (options.params.min) {
414 | setValidationValues(options, "minlength", options.params.min);
415 | }
416 | if (options.params.nonalphamin) {
417 | setValidationValues(options, "nonalphamin", options.params.nonalphamin);
418 | }
419 | if (options.params.regex) {
420 | setValidationValues(options, "regex", options.params.regex);
421 | }
422 | });
423 | adapters.add("fileextensions", ["extensions"], function (options) {
424 | setValidationValues(options, "extension", options.params.extensions);
425 | });
426 |
427 | $(function () {
428 | $jQval.unobtrusive.parse(document);
429 | });
430 |
431 | return $jQval.unobtrusive;
432 | }));
433 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | // Unobtrusive validation support library for jQuery and jQuery Validate
2 | // Copyright (c) .NET Foundation. All rights reserved.
3 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
4 | // @version v3.2.11
5 | !function(a){"function"==typeof define&&define.amd?define("jquery.validate.unobtrusive",["jquery-validation"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery-validation")):jQuery.validator.unobtrusive=a(jQuery)}(function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a(" ").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function u(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=f.unobtrusive.options||{},u=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),u("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),u("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),u("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var m,f=a.validator,v="unobtrusiveValidation";return f.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=u(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){f.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=u(this);a&&a.attachValidation()})}},m=f.unobtrusive.adapters,m.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},m.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},m.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},m.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},f.addMethod("__dummy__",function(a,e,n){return!0}),f.addMethod("regex",function(a,e,n){var t;return!!this.optional(e)||(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),f.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),f.methods.extension?(m.addSingleVal("accept","mimtype"),m.addSingleVal("extension","extension")):m.addSingleVal("extension","extension","accept"),m.addSingleVal("regex","pattern"),m.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),m.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),m.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),m.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),m.add("required",function(a){"INPUT"===a.element.tagName.toUpperCase()&&"CHECKBOX"===a.element.type.toUpperCase()||e(a,"required",!0)}),m.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),m.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),m.add("fileextensions",["extensions"],function(a){e(a,"extension",a.params.extensions)}),a(function(){f.unobtrusive.parse(document)}),f.unobtrusive});
6 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/jquery-validation/dist/additional-methods.min.js:
--------------------------------------------------------------------------------
1 | /*! jQuery Validation Plugin - v1.17.0 - 7/29/2017
2 | * https://jqueryvalidation.org/
3 | * Copyright (c) 2017 Jörn Zaefferer; Licensed MIT */
4 | !function(a){"function"==typeof define&&define.amd?define(["jquery","./jquery.validate.min"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){return function(){function b(a){return a.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," ").replace(/[.(),;:!?%#$'\"_+=\/\-“”’]*/g,"")}a.validator.addMethod("maxWords",function(a,c,d){return this.optional(c)||b(a).match(/\b\w+\b/g).length<=d},a.validator.format("Please enter {0} words or less.")),a.validator.addMethod("minWords",function(a,c,d){return this.optional(c)||b(a).match(/\b\w+\b/g).length>=d},a.validator.format("Please enter at least {0} words.")),a.validator.addMethod("rangeWords",function(a,c,d){var e=b(a),f=/\b\w+\b/g;return this.optional(c)||e.match(f).length>=d[0]&&e.match(f).length<=d[1]},a.validator.format("Please enter between {0} and {1} words."))}(),a.validator.addMethod("accept",function(b,c,d){var e,f,g,h="string"==typeof d?d.replace(/\s/g,""):"image/*",i=this.optional(c);if(i)return i;if("file"===a(c).attr("type")&&(h=h.replace(/[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g,"\\$&").replace(/,/g,"|").replace(/\/\*/g,"/.*"),c.files&&c.files.length))for(g=new RegExp(".?("+h+")$","i"),e=0;e9?"0":f,g="JABCDEFGHI".substr(f,1).toString(),i.match(/[ABEH]/)?k===f:i.match(/[KPQS]/)?k===g:k===f||k===g},"Please specify a valid CIF number."),a.validator.addMethod("cpfBR",function(a){if(a=a.replace(/([~!@#$%^&*()_+=`{}\[\]\-|\\:;'<>,.\/? ])+/g,""),11!==a.length)return!1;var b,c,d,e,f=0;if(b=parseInt(a.substring(9,10),10),c=parseInt(a.substring(10,11),10),d=function(a,b){var c=10*a%11;return 10!==c&&11!==c||(c=0),c===b},""===a||"00000000000"===a||"11111111111"===a||"22222222222"===a||"33333333333"===a||"44444444444"===a||"55555555555"===a||"66666666666"===a||"77777777777"===a||"88888888888"===a||"99999999999"===a)return!1;for(e=1;e<=9;e++)f+=parseInt(a.substring(e-1,e),10)*(11-e);if(d(f,b)){for(f=0,e=1;e<=10;e++)f+=parseInt(a.substring(e-1,e),10)*(12-e);return d(f,c)}return!1},"Please specify a valid CPF number"),a.validator.addMethod("creditcard",function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 \-]+/.test(a))return!1;var c,d,e=0,f=0,g=!1;if(a=a.replace(/\D/g,""),a.length<13||a.length>19)return!1;for(c=a.length-1;c>=0;c--)d=a.charAt(c),f=parseInt(d,10),g&&(f*=2)>9&&(f-=9),e+=f,g=!g;return e%10===0},"Please enter a valid credit card number."),a.validator.addMethod("creditcardtypes",function(a,b,c){if(/[^0-9\-]+/.test(a))return!1;a=a.replace(/\D/g,"");var d=0;return c.mastercard&&(d|=1),c.visa&&(d|=2),c.amex&&(d|=4),c.dinersclub&&(d|=8),c.enroute&&(d|=16),c.discover&&(d|=32),c.jcb&&(d|=64),c.unknown&&(d|=128),c.all&&(d=255),1&d&&/^(5[12345])/.test(a)?16===a.length:2&d&&/^(4)/.test(a)?16===a.length:4&d&&/^(3[47])/.test(a)?15===a.length:8&d&&/^(3(0[012345]|[68]))/.test(a)?14===a.length:16&d&&/^(2(014|149))/.test(a)?15===a.length:32&d&&/^(6011)/.test(a)?16===a.length:64&d&&/^(3)/.test(a)?16===a.length:64&d&&/^(2131|1800)/.test(a)?15===a.length:!!(128&d)},"Please enter a valid credit card number."),a.validator.addMethod("currency",function(a,b,c){var d,e="string"==typeof c,f=e?c:c[0],g=!!e||c[1];return f=f.replace(/,/g,""),f=g?f+"]":f+"]?",d="^["+f+"([1-9]{1}[0-9]{0,2}(\\,[0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)$",d=new RegExp(d),this.optional(b)||d.test(a)},"Please specify a valid currency"),a.validator.addMethod("dateFA",function(a,b){return this.optional(b)||/^[1-4]\d{3}\/((0?[1-6]\/((3[0-1])|([1-2][0-9])|(0?[1-9])))|((1[0-2]|(0?[7-9]))\/(30|([1-2][0-9])|(0?[1-9]))))$/.test(a)},a.validator.messages.date),a.validator.addMethod("dateITA",function(a,b){var c,d,e,f,g,h=!1,i=/^\d{1,2}\/\d{1,2}\/\d{4}$/;return i.test(a)?(c=a.split("/"),d=parseInt(c[0],10),e=parseInt(c[1],10),f=parseInt(c[2],10),g=new Date(Date.UTC(f,e-1,d,12,0,0,0)),h=g.getUTCFullYear()===f&&g.getUTCMonth()===e-1&&g.getUTCDate()===d):h=!1,this.optional(b)||h},a.validator.messages.date),a.validator.addMethod("dateNL",function(a,b){return this.optional(b)||/^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test(a)},a.validator.messages.date),a.validator.addMethod("extension",function(a,b,c){return c="string"==typeof c?c.replace(/,/g,"|"):"png|jpe?g|gif",this.optional(b)||a.match(new RegExp("\\.("+c+")$","i"))},a.validator.format("Please enter a value with a valid extension.")),a.validator.addMethod("giroaccountNL",function(a,b){return this.optional(b)||/^[0-9]{1,7}$/.test(a)},"Please specify a valid giro account number"),a.validator.addMethod("iban",function(a,b){if(this.optional(b))return!0;var c,d,e,f,g,h,i,j,k,l=a.replace(/ /g,"").toUpperCase(),m="",n=!0,o="",p="",q=5;if(l.length9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[1345789]\d{2}|624)\s?\d{3}\s?\d{3})$/)},"Please specify a valid mobile number"),a.validator.addMethod("netmask",function(a,b){return this.optional(b)||/^(254|252|248|240|224|192|128)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(254|252|248|240|224|192|128|0)/i.test(a)},"Please enter a valid netmask."),a.validator.addMethod("nieES",function(a,b){"use strict";if(this.optional(b))return!0;var c,d=new RegExp(/^[MXYZ]{1}[0-9]{7,8}[TRWAGMYFPDXBNJZSQVHLCKET]{1}$/gi),e="TRWAGMYFPDXBNJZSQVHLCKET",f=a.substr(a.length-1).toUpperCase();return a=a.toString().toUpperCase(),!(a.length>10||a.length<9||!d.test(a))&&(a=a.replace(/^[X]/,"0").replace(/^[Y]/,"1").replace(/^[Z]/,"2"),c=9===a.length?a.substr(0,8):a.substr(0,9),e.charAt(parseInt(c,10)%23)===f)},"Please specify a valid NIE number."),a.validator.addMethod("nifES",function(a,b){"use strict";return!!this.optional(b)||(a=a.toUpperCase(),!!a.match("((^[A-Z]{1}[0-9]{7}[A-Z0-9]{1}$|^[T]{1}[A-Z0-9]{8}$)|^[0-9]{8}[A-Z]{1}$)")&&(/^[0-9]{8}[A-Z]{1}$/.test(a)?"TRWAGMYFPDXBNJZSQVHLCKE".charAt(a.substring(8,0)%23)===a.charAt(8):!!/^[KLM]{1}/.test(a)&&a[8]==="TRWAGMYFPDXBNJZSQVHLCKE".charAt(a.substring(8,1)%23)))},"Please specify a valid NIF number."),a.validator.addMethod("nipPL",function(a){"use strict";if(a=a.replace(/[^0-9]/g,""),10!==a.length)return!1;for(var b=[6,5,7,2,3,4,5,6,7],c=0,d=0;d<9;d++)c+=b[d]*a[d];var e=c%11,f=10===e?0:e;return f===parseInt(a[9],10)},"Please specify a valid NIP number."),a.validator.addMethod("notEqualTo",function(b,c,d){return this.optional(c)||!a.validator.methods.equalTo.call(this,b,c,d)},"Please enter a different value, values must not be the same."),a.validator.addMethod("nowhitespace",function(a,b){return this.optional(b)||/^\S+$/i.test(a)},"No white space please"),a.validator.addMethod("pattern",function(a,b,c){return!!this.optional(b)||("string"==typeof c&&(c=new RegExp("^(?:"+c+")$")),c.test(a))},"Invalid format."),a.validator.addMethod("phoneNL",function(a,b){return this.optional(b)||/^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test(a)},"Please specify a valid phone number."),a.validator.addMethod("phonesUK",function(a,b){return a=a.replace(/\(|\)|\s+|-/g,""),this.optional(b)||a.length>9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[1345789]\d{8}|624\d{6})))$/)},"Please specify a valid uk phone number"),a.validator.addMethod("phoneUK",function(a,b){return a=a.replace(/\(|\)|\s+|-/g,""),this.optional(b)||a.length>9&&a.match(/^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/)},"Please specify a valid phone number"),a.validator.addMethod("phoneUS",function(a,b){return a=a.replace(/\s+/g,""),this.optional(b)||a.length>9&&a.match(/^(\+?1-?)?(\([2-9]([02-9]\d|1[02-9])\)|[2-9]([02-9]\d|1[02-9]))-?[2-9]([02-9]\d|1[02-9])-?\d{4}$/)},"Please specify a valid phone number"),a.validator.addMethod("postalcodeBR",function(a,b){return this.optional(b)||/^\d{2}.\d{3}-\d{3}?$|^\d{5}-?\d{3}?$/.test(a)},"Informe um CEP válido."),a.validator.addMethod("postalCodeCA",function(a,b){return this.optional(b)||/^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ] *\d[ABCEGHJKLMNPRSTVWXYZ]\d$/i.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postalcodeIT",function(a,b){return this.optional(b)||/^\d{5}$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postalcodeNL",function(a,b){return this.optional(b)||/^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test(a)},"Please specify a valid postal code"),a.validator.addMethod("postcodeUK",function(a,b){return this.optional(b)||/^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test(a)},"Please specify a valid UK postcode"),a.validator.addMethod("require_from_group",function(b,c,d){var e=a(d[1],c.form),f=e.eq(0),g=f.data("valid_req_grp")?f.data("valid_req_grp"):a.extend({},this),h=e.filter(function(){return g.elementValue(this)}).length>=d[0];return f.data("valid_req_grp",g),a(c).data("being_validated")||(e.data("being_validated",!0),e.each(function(){g.element(this)}),e.data("being_validated",!1)),h},a.validator.format("Please fill at least {0} of these fields.")),a.validator.addMethod("skip_or_fill_minimum",function(b,c,d){var e=a(d[1],c.form),f=e.eq(0),g=f.data("valid_skip")?f.data("valid_skip"):a.extend({},this),h=e.filter(function(){return g.elementValue(this)}).length,i=0===h||h>=d[0];return f.data("valid_skip",g),a(c).data("being_validated")||(e.data("being_validated",!0),e.each(function(){g.element(this)}),e.data("being_validated",!1)),i},a.validator.format("Please either skip these fields or fill at least {0} of them.")),a.validator.addMethod("stateUS",function(a,b,c){var d,e="undefined"==typeof c,f=!e&&"undefined"!=typeof c.caseSensitive&&c.caseSensitive,g=!e&&"undefined"!=typeof c.includeTerritories&&c.includeTerritories,h=!e&&"undefined"!=typeof c.includeMilitary&&c.includeMilitary;return d=g||h?g&&h?"^(A[AEKLPRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$":g?"^(A[KLRSZ]|C[AOT]|D[CE]|FL|G[AU]|HI|I[ADLN]|K[SY]|LA|M[ADEINOPST]|N[CDEHJMVY]|O[HKR]|P[AR]|RI|S[CD]|T[NX]|UT|V[AIT]|W[AIVY])$":"^(A[AEKLPRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$":"^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$",d=f?new RegExp(d):new RegExp(d,"i"),this.optional(b)||d.test(a)},"Please specify a valid state"),a.validator.addMethod("strippedminlength",function(b,c,d){return a(b).text().length>=d},a.validator.format("Please enter at least {0} characters")),a.validator.addMethod("time",function(a,b){return this.optional(b)||/^([01]\d|2[0-3]|[0-9])(:[0-5]\d){1,2}$/.test(a)},"Please enter a valid time, between 00:00 and 23:59"),a.validator.addMethod("time12h",function(a,b){return this.optional(b)||/^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test(a)},"Please enter a valid time in 12-hour am/pm format"),a.validator.addMethod("url2",function(a,b){return this.optional(b)||/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)},a.validator.messages.url),a.validator.addMethod("vinUS",function(a){if(17!==a.length)return!1;var b,c,d,e,f,g,h=["A","B","C","D","E","F","G","H","J","K","L","M","N","P","R","S","T","U","V","W","X","Y","Z"],i=[1,2,3,4,5,6,7,8,1,2,3,4,5,7,9,2,3,4,5,6,7,8,9],j=[8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2],k=0;for(b=0;b<17;b++){if(e=j[b],d=a.slice(b,b+1),8===b&&(g=d),isNaN(d)){for(c=0;c ").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),!c.settings.submitHandler||(e=c.settings.submitHandler.call(c,c.currentForm,b),d&&d.remove(),void 0!==e&&e)}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){var d,e,f,g,h,i,j=this[0];if(null!=j&&(!j.form&&j.hasAttribute("contenteditable")&&(j.form=this.closest("form")[0],j.name=this.attr("name")),null!=j.form)){if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(a,b){i[b]=f[b],delete f[b]}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g)),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}}),a.extend(a.expr.pseudos||a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){var c=a(b).val();return null!==c&&!!a.trim(""+c)},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",pendingClass:"pending",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||a.inArray(c.keyCode,d)!==-1||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}."),step:a.validator.format("Please enter a multiple of {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){!this.form&&this.hasAttribute("contenteditable")&&(this.form=a(this).closest("form")[0],this.name=a(this).attr("name"));var c=a.data(this.form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!a(this).is(e.ignore)&&e[d].call(c,this,b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on("focusin.validate focusout.validate keyup.validate",":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox'], [contenteditable], [type='button']",b).on("click.validate","select, option, [type='radio'], [type='checkbox']",b),this.settings.invalidHandler&&a(this.currentForm).on("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c,d,e=this.clean(b),f=this.validationTargetFor(e),g=this,h=!0;return void 0===f?delete this.invalid[e.name]:(this.prepareElement(f),this.currentElements=a(f),d=this.groups[f.name],d&&a.each(this.groups,function(a,b){b===d&&a!==f.name&&(e=g.validationTargetFor(g.clean(g.findByName(a))),e&&e.name in g.invalid&&(g.currentElements.push(e),h=g.check(e)&&h))}),c=this.check(f)!==!1,h=h&&c,c?this.invalid[f.name]=!1:this.invalid[f.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),a(b).attr("aria-invalid",!c)),h},showErrors:function(b){if(b){var c=this;a.extend(this.errorMap,b),this.errorList=a.map(this.errorMap,function(a,b){return{message:a,element:c.findByName(b)[0]}}),this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.invalid={},this.submitted={},this.prepareForm(),this.hideErrors();var b=this.elements().removeData("previousValue").removeAttr("aria-invalid");this.resetElements(b)},resetElements:function(a){var b;if(this.settings.unhighlight)for(b=0;a[b];b++)this.settings.unhighlight.call(this,a[b],this.settings.errorClass,""),this.findByName(a[b].name).removeClass(this.settings.validClass);else a.removeClass(this.settings.errorClass).removeClass(this.settings.validClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)void 0!==a[b]&&null!==a[b]&&a[b]!==!1&&c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea, [contenteditable]").not(":submit, :reset, :image, :disabled").not(this.settings.ignore).filter(function(){var d=this.name||a(this).attr("name");return!d&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.hasAttribute("contenteditable")&&(this.form=a(this).closest("form")[0],this.name=d),!(d in c||!b.objectLength(a(this).rules()))&&(c[d]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},resetInternals:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([])},reset:function(){this.resetInternals(),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d,e=a(b),f=b.type;return"radio"===f||"checkbox"===f?this.findByName(b.name).filter(":checked").val():"number"===f&&"undefined"!=typeof b.validity?b.validity.badInput?"NaN":e.val():(c=b.hasAttribute("contenteditable")?e.text():e.val(),"file"===f?"C:\\fakepath\\"===c.substr(0,12)?c.substr(12):(d=c.lastIndexOf("/"),d>=0?c.substr(d+1):(d=c.lastIndexOf("\\"),d>=0?c.substr(d+1):c)):"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f,g=a(b).rules(),h=a.map(g,function(a,b){return b}).length,i=!1,j=this.elementValue(b);if("function"==typeof g.normalizer?f=g.normalizer:"function"==typeof this.settings.normalizer&&(f=this.settings.normalizer),f){if(j=f.call(b,j),"string"!=typeof j)throw new TypeError("The normalizer should return a string value.");delete g.normalizer}for(d in g){e={method:d,parameters:g[d]};try{if(c=a.validator.methods[d].call(this,j,b,e.parameters),"dependency-mismatch"===c&&1===h){i=!0;continue}if(i=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(k){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",k),k instanceof TypeError&&(k.message+=". Exception occurred when checking element "+b.id+", check the '"+e.method+"' method."),k}}if(!i)return this.objectLength(g)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+b.name+""),e=/\$?\{(\d+)\}/g;return"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),d},formatAndAdd:function(a,b){var c=this.defaultMessage(a,b);this.errorList.push({message:c,element:a,method:b.method}),this.errorMap[a.name]=c,this.submitted[a.name]=c},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g,h=this.errorsFor(b),i=this.idOrName(b),j=a(b).attr("aria-describedby");h.length?(h.removeClass(this.settings.validClass).addClass(this.settings.errorClass),h.html(c)):(h=a("<"+this.settings.errorElement+">").attr("id",i+"-error").addClass(this.settings.errorClass).html(c||""),d=h,this.settings.wrapper&&(d=h.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement.call(this,d,a(b)):d.insertAfter(b),h.is("label")?h.attr("for",i):0===h.parents("label[for='"+this.escapeCssMeta(i)+"']").length&&(f=h.attr("id"),j?j.match(new RegExp("\\b"+this.escapeCssMeta(f)+"\\b"))||(j+=" "+f):j=f,a(b).attr("aria-describedby",j),e=this.groups[b.name],e&&(g=this,a.each(g.groups,function(b,c){c===e&&a("[name='"+g.escapeCssMeta(b)+"']",g.currentForm).attr("aria-describedby",h.attr("id"))})))),!c&&this.settings.success&&(h.text(""),"string"==typeof this.settings.success?h.addClass(this.settings.success):this.settings.success(h,b)),this.toShow=this.toShow.add(h)},errorsFor:function(b){var c=this.escapeCssMeta(this.idOrName(b)),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+this.escapeCssMeta(d).replace(/\s+/g,", #")),this.errors().filter(e)},escapeCssMeta:function(a){return a.replace(/([\\!"#$%&'()*+,.\/:;<=>?@\[\]^`{|}~])/g,"\\$1")},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+this.escapeCssMeta(b)+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return!this.dependTypes[typeof a]||this.dependTypes[typeof a](a,b)},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(b){this.pending[b.name]||(this.pendingRequest++,a(b).addClass(this.settings.pendingClass),this.pending[b.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],a(b).removeClass(this.settings.pendingClass),c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.submitButton&&a("input:hidden[name='"+this.submitButton.name+"']",this.currentForm).remove(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b,c){return c="string"==typeof c&&c||"remote",a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,{method:c})})},destroy:function(){this.resetForm(),a(this.currentForm).off(".validate").removeData("validator").find(".validate-equalTo-blur").off(".validate-equalTo").removeClass("validate-equalTo-blur")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max|step/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&"range"!==b&&(a[c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0===e.param||e.param:(a.data(c.form,"validator").resetElements(a(c)),delete b[d])}}),a.each(b,function(d,e){b[d]=a.isFunction(e)&&"normalizer"!==d?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:b.length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[\/?#]\S*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e<=d},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||a<=c},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},step:function(b,c,d){var e,f=a(c).attr("type"),g="Step attribute on input type "+f+" is not supported.",h=["text","number","range"],i=new RegExp("\\b"+f+"\\b"),j=f&&!i.test(h.join()),k=function(a){var b=(""+a).match(/(?:\.(\d+))?$/);return b&&b[1]?b[1].length:0},l=function(a){return Math.round(a*Math.pow(10,e))},m=!0;if(j)throw new Error(g);return e=k(d),(k(b)>e||l(b)%l(d)!==0)&&(m=!1),this.optional(c)||m},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.not(".validate-equalTo-blur").length&&e.addClass("validate-equalTo-blur").on("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d,e){if(this.optional(c))return"dependency-mismatch";e="string"==typeof e&&e||"remote";var f,g,h,i=this.previousValue(c,e);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),i.originalMessage=i.originalMessage||this.settings.messages[c.name][e],this.settings.messages[c.name][e]=i.message,d="string"==typeof d&&{url:d}||d,h=a.param(a.extend({data:b},d.data)),i.old===h?i.valid:(i.old=h,f=this,this.startRequest(c),g={},g[c.name]=b,a.ajax(a.extend(!0,{mode:"abort",port:"validate"+c.name,dataType:"json",data:g,context:f.currentForm,success:function(a){var d,g,h,j=a===!0||"true"===a;f.settings.messages[c.name][e]=i.originalMessage,j?(h=f.formSubmitted,f.resetInternals(),f.toHide=f.errorsFor(c),f.formSubmitted=h,f.successList.push(c),f.invalid[c.name]=!1,f.showErrors()):(d={},g=a||f.defaultMessage(c,{method:e,parameters:b}),d[c.name]=i.message=g,f.invalid[c.name]=!0,f.showErrors(d)),i.valid=j,f.stopRequest(c,j)}},d)),"pending")}}});var b,c={};return a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)}),a});
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Example/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors, https://js.foundation/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.SystemTextJson/Castle.DynamicLinqQueryBuilder.SystemTextJson.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {22861CF7-71BB-44AF-9630-AC3A59F36838}
7 | Library
8 | Properties
9 | Castle.DynamicLinqQueryBuilder.SystemTextJson
10 | Castle.DynamicLinqQueryBuilder.SystemTextJson
11 | netstandard2.0
12 | 512
13 |
14 | true
15 | 1.3.4
16 | 1.3.4.0
17 | 1.3.4.0
18 | Grant Hamm
19 | N/A
20 | Dynamic Linq Query Builder - System.Text.Json Extension
21 | A companion package for those using System.Text.Json
22 | This library is licensed MIT, in the public domain
23 | MIT
24 | https://github.com/tghamm/dynamic-linq-query-builder/
25 | https://github.com/tghamm/dynamic-linq-query-builder/
26 | Git
27 | jquery-query-builder generic query generator linq javascript
28 | Minor Enhancements
29 | True
30 | README.md
31 | true
32 | true
33 | snupkg
34 | latest
35 | Debug;Release;LocalTest
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | True
48 | \
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.SystemTextJson/SystemTextJsonFilterRule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 |
5 |
6 | namespace Castle.DynamicLinqQueryBuilder.SystemTextJson
7 | {
8 |
9 | using System.Text.Json;
10 | public class SystemTextJsonFilterRule : IFilterRule
11 | {
12 | ///
13 | /// Condition - acceptable values are "and" and "or".
14 | ///
15 | ///
16 | /// The condition.
17 | ///
18 | public string Condition { get; set; }
19 | ///
20 | /// The name of the field that the filter applies to.
21 | ///
22 | ///
23 | /// The field.
24 | ///
25 | public string Field { get; set; }
26 | ///
27 | /// Gets or sets the identifier.
28 | ///
29 | ///
30 | /// The identifier.
31 | ///
32 | public string Id { get; set; }
33 | ///
34 | /// Gets or sets the input.
35 | ///
36 | ///
37 | /// The input.
38 | ///
39 | public string Input { get; set; }
40 | ///
41 | /// Gets or sets the operator.
42 | ///
43 | ///
44 | /// The operator.
45 | ///
46 | public string Operator { get; set; }
47 | ///
48 | /// Gets or sets nested filter rules.
49 | ///
50 | ///
51 | /// The rules.
52 | ///
53 | public List Rules { get; set; }
54 | ///
55 | /// Gets or sets the type. Supported values are "integer", "double", "string", "date", "datetime", "guid", and "boolean".
56 | ///
57 | ///
58 | /// The type.
59 | ///
60 | public string Type { get; set; }
61 |
62 | private Object _Value { get; set; }
63 | ///
64 | /// Gets or sets the value of the filter.
65 | ///
66 | ///
67 | /// The value.
68 | ///
69 | ///
70 | public object Value
71 | {
72 | get
73 | {
74 | // See if this is a JsonElement
75 | if (_Value is JsonElement jsonValue)
76 | {
77 | System.Type myType = QueryBuilder.GetCSharpType(Type);
78 |
79 | try
80 | {
81 | if (jsonValue.ValueKind == JsonValueKind.Array)
82 | {
83 | if (myType.Name == "DateOnly")
84 | myType = typeof(DateTime);
85 | var outList = Array.CreateInstance(myType, jsonValue.GetArrayLength());
86 | var enumerator = 0;
87 |
88 | foreach (var item in jsonValue.EnumerateArray())
89 | {
90 | object typedItem = GetJsonElementAsType(item);
91 | outList.SetValue(typedItem, enumerator);
92 | enumerator++;
93 | }
94 |
95 | return outList;
96 | }
97 | else
98 | {
99 | return GetJsonElementAsType(jsonValue);
100 | }
101 | }
102 | catch (Exception ex)
103 | {
104 | throw new InvalidCastException("Error converting JsonElement to .Net Type", ex);
105 | }
106 | }
107 |
108 | return _Value;
109 | }
110 |
111 | set
112 | {
113 | _Value = value;
114 | }
115 | }
116 |
117 |
118 | IEnumerable IFilterRule.Rules => Rules;
119 |
120 | private object GetJsonElementAsType(JsonElement element)
121 | {
122 | Object o = null;
123 | switch (this.Type)
124 | {
125 | case "integer":
126 | o = element.ValueKind == JsonValueKind.Number
127 | ? element.GetInt32()
128 | : Int32.Parse(element.GetString());
129 | break;
130 | case "double":
131 | o = element.ValueKind == JsonValueKind.Number
132 | ? element.GetDouble()
133 | : double.Parse(element.ToString());
134 | break;
135 | case "string":
136 | o = element.ToString();
137 | break;
138 | case "date":
139 | case "datetime":
140 | o = DateTime.Parse(element.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
141 | break;
142 | case "boolean":
143 | o = ((element.ValueKind == JsonValueKind.True) || (element.ValueKind == JsonValueKind.False))
144 | ? element.GetBoolean()
145 | : bool.Parse(element.ToString());
146 | break;
147 | case "guid":
148 | o = element.GetGuid();
149 | break;
150 | }
151 |
152 | return o;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/Castle.DynamicLinqQueryBuilder.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 | false
7 |
8 | latest
9 |
10 | Debug;Release;LocalTest
11 |
12 |
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 |
21 | all
22 | runtime; build; native; contentfiles; analyzers; buildtransitive
23 |
24 |
25 |
26 |
27 | all
28 | runtime; build; native; contentfiles; analyzers; buildtransitive
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/Culture/CultureTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Castle.DynamicLinqQueryBuilder.Tests.Rules;
10 | using NUnit.Framework;
11 |
12 | namespace Castle.DynamicLinqQueryBuilder.Tests.Culture
13 | {
14 | [ExcludeFromCodeCoverage]
15 | [TestFixture]
16 | public class CultureTests
17 | {
18 | IQueryable StartingQuery;
19 | IQueryable StartingDateQuery;
20 |
21 | [SetUp]
22 | public void Setup()
23 | {
24 | StartingQuery = Rules.Tests.GetExpressionTreeData().AsQueryable();
25 | StartingDateQuery = Rules.Tests.GetDateExpressionTreeData().AsQueryable();
26 | Thread.CurrentThread.CurrentCulture = new CultureInfo("es-ES");
27 | Thread.CurrentThread.CurrentUICulture = new CultureInfo("es-ES");
28 | }
29 | [Test]
30 | public void TestBetween()
31 | {
32 | //expect 3 entries to match for a double field
33 | var statValueFilter = new QueryBuilderFilterRule
34 | {
35 | Condition = "and",
36 | Rules = new List
37 | {
38 | new QueryBuilderFilterRule
39 | {
40 | Condition = "and",
41 | Field = "StatValue",
42 | Id = "StatValue",
43 | Input = "NA",
44 | Operator = "between",
45 | Type = "double",
46 | Value = new[] { "1,0", "1,12" }
47 | }
48 | }
49 | };
50 | var statValueFilterList = StartingQuery.BuildQuery(statValueFilter, new BuildExpressionOptions()
51 | {
52 | CultureInfo = new CultureInfo("es-ES")
53 | }).ToList();
54 | Assert.IsTrue(statValueFilterList != null);
55 | Assert.IsTrue(statValueFilterList.Count == 3);
56 | }
57 |
58 | [Test]
59 | public void TestDateInCulture()
60 | {
61 | //expect 4 entries to match for a Date comparison
62 | var lastModifiedFilter = new QueryBuilderFilterRule
63 | {
64 | Condition = "and",
65 | Rules = new List
66 | {
67 | new QueryBuilderFilterRule
68 | {
69 | Condition = "and",
70 | Field = "LastModified",
71 | Id = "LastModified",
72 | Input = "NA",
73 | Operator = "in",
74 | Type = "datetime",
75 | Value = new[] { DateTime.UtcNow.Date.ToString(), DateTime.UtcNow.Date.ToString() }
76 | }
77 | }
78 | };
79 | var lastModifiedFilterList = StartingQuery.BuildQuery(lastModifiedFilter, new BuildExpressionOptions()
80 | {
81 | CultureInfo = new CultureInfo("es-ES")
82 | }).ToList();
83 | Assert.IsTrue(lastModifiedFilterList != null);
84 | Assert.IsTrue(lastModifiedFilterList.Count == 4);
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/CustomOperators/CustomOperatorsTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using Castle.DynamicLinqQueryBuilder.Tests.Helpers;
7 | using NUnit.Framework;
8 |
9 | namespace Castle.DynamicLinqQueryBuilder.Tests.CustomOperators
10 | {
11 | public class MyRecord {
12 | public string UserHostAddress { get; set; }
13 | }
14 |
15 | public class InIpRangeOperator : IFilterOperator
16 | {
17 | public string Operator => "in_ip_range";
18 |
19 | public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options)
20 | {
21 |
22 | return Expression.Call(this.GetType().GetMethod("ContainsIP"), new[] { propertyExp, Expression.Constant(rule.Value) });
23 |
24 | }
25 | public static bool ContainsIP(string ip, string[] ranges) {
26 | return true; //TODO: implement custom ip range validation
27 | }
28 | }
29 |
30 | [ExcludeFromCodeCoverage]
31 | [TestFixture]
32 | public class CustomOperatorsTests
33 | {
34 | [Test]
35 | public void CustomInOperator_Test() {
36 | var rec = new MyRecord();
37 |
38 | rec.UserHostAddress = "8.10.8.13";
39 |
40 | var records = new List() { rec };
41 |
42 | var myFilter = new QueryBuilderFilterRule()
43 | {
44 | Condition = "and",
45 | Rules = new List()
46 | {
47 | new QueryBuilderFilterRule()
48 | {
49 | Condition = "and",
50 | Field = "UserHostAddress",
51 | Operator = "in_ip_range",
52 | Type = "string",
53 | Value = new [] { "10.10.10.*" }
54 | }
55 | }
56 | };
57 | var options = new BuildExpressionOptions();
58 | options.Operators = new List() { new InIpRangeOperator()};
59 | var result = records.AsQueryable().BuildQuery(myFilter, options).ToList();
60 | var len = result.Count;
61 | Assert.AreEqual(1, len);
62 | }
63 |
64 | [Test]
65 | public void UnknownOperator_Test1()
66 | {
67 | var rec = new MyRecord();
68 |
69 | rec.UserHostAddress = "8.10.8.13";
70 |
71 | var records = new List() { rec };
72 |
73 | var myFilter = new QueryBuilderFilterRule()
74 | {
75 | Condition = "and",
76 | Rules = new List()
77 | {
78 | new QueryBuilderFilterRule()
79 | {
80 | Condition = "and",
81 | Field = "UserHostAddress",
82 | Operator = "in_ip_range",
83 | Type = "string",
84 | Value = new [] { "10.10.10.*" }
85 | }
86 | }
87 | };
88 |
89 | ExceptionAssert.Throws(() =>
90 | {
91 | var result = records.AsQueryable().BuildQuery(myFilter).ToList();
92 | });
93 | }
94 |
95 | [Test]
96 | public void UnknownOperator_Test2()
97 | {
98 | var rec = new MyRecord();
99 |
100 | rec.UserHostAddress = "8.10.8.13";
101 |
102 | var records = new List() { rec };
103 |
104 | var myFilter = new QueryBuilderFilterRule()
105 | {
106 | Condition = "and",
107 | Rules = new List()
108 | {
109 | new QueryBuilderFilterRule()
110 | {
111 | Condition = "and",
112 | Field = "UserHostAddress",
113 | Operator = "in_ip_range_spelledwrong",
114 | Type = "string",
115 | Value = new [] { "10.10.10.*" }
116 | }
117 | }
118 | };
119 | var options = new BuildExpressionOptions();
120 | options.Operators = new List() { new InIpRangeOperator() };
121 | ExceptionAssert.Throws(() =>
122 | {
123 | var result = records.AsQueryable().BuildQuery(myFilter, options).ToList();
124 | });
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/Database/Restaurant.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics.CodeAnalysis;
3 | using MongoDB.Bson;
4 | using MongoDB.Bson.Serialization.Attributes;
5 |
6 | namespace Castle.DynamicLinqQueryBuilder.Tests.Database;
7 |
8 |
9 | [ExcludeFromCodeCoverage]
10 | public class Restaurant
11 | {
12 | public ObjectId Id { get; set; }
13 | public string Name { get; set; }
14 | [BsonElement("restaurant_id")]
15 | public string RestaurantId { get; set; }
16 | public Dictionary Details { get; set; }
17 | [BsonElement("status")]
18 | public Status Status { get; set; }
19 | }
20 |
21 | public enum Status
22 | {
23 | Open,
24 | Closed
25 | }
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/Database/StoreContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel.DataAnnotations;
4 | using System.ComponentModel.DataAnnotations.Schema;
5 | using System.Diagnostics.CodeAnalysis;
6 | using Microsoft.EntityFrameworkCore;
7 | using Microsoft.EntityFrameworkCore.Design;
8 |
9 | namespace Castle.DynamicLinqQueryBuilder.Tests.Database
10 | {
11 | [ExcludeFromCodeCoverage]
12 | public class StoreContext: DbContext
13 | {
14 | public StoreContext(DbContextOptions options)
15 | : base(options)
16 | {
17 | }
18 |
19 | public DbSet Stores { get; set; }
20 | public DbSet Products { get; set; }
21 | public DbSet StoreOwners { get; set; }
22 | }
23 | [ExcludeFromCodeCoverage]
24 | public class StoreContextFactory : IDesignTimeDbContextFactory
25 | {
26 | public StoreContext CreateDbContext(string[] args)
27 | {
28 | var optionsBuilder = new DbContextOptionsBuilder();
29 | optionsBuilder.UseSqlite("Filename=:memory:");
30 |
31 | return new StoreContext(optionsBuilder.Options);
32 | }
33 | }
34 | [ExcludeFromCodeCoverage]
35 | public class Store
36 | {
37 | [Key]
38 | [DatabaseGenerated(DatabaseGeneratedOption.None)]
39 | public Guid StoreId { get; set; }
40 |
41 | public string StoreName { get; set; }
42 | public DateTime OpenDate { get; set; }
43 | public double TotalRevenue { get; set; }
44 |
45 | public virtual List Products { get; set; }
46 | public virtual StoreOwner StoreOwner { get; set; }
47 | }
48 |
49 | public class StoreOwner
50 | {
51 | [Key]
52 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
53 | public int StoreOwnerId { get; set; }
54 | public string StoreOwnerName { get; set; }
55 | [ForeignKey("Store")]
56 | public Guid StoreId { get; set; }
57 |
58 | public virtual Store Store { get; set; }
59 | }
60 | [ExcludeFromCodeCoverage]
61 | public class Product
62 | {
63 | [Key]
64 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
65 | public int ProductId { get; set; }
66 | [ForeignKey("Store")]
67 | public Guid StoreId { get; set; }
68 |
69 | public virtual Store Store { get; set; }
70 |
71 | public string ProductName { get; set; }
72 | public double ProductPrice { get; set; }
73 |
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/Helpers/ExceptionAssert.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace Castle.DynamicLinqQueryBuilder.Tests.Helpers
5 | {
6 | [ExcludeFromCodeCoverage]
7 | public static class ExceptionAssert
8 | {
9 | public static void Throws(Action func) where T : Exception
10 | {
11 | var exceptionThrown = false;
12 | try
13 | {
14 | func.Invoke();
15 | }
16 |
17 | catch (T)
18 | {
19 | exceptionThrown = true;
20 | }
21 | catch (Exception)
22 | {
23 |
24 | }
25 | if (!exceptionThrown)
26 | {
27 | throw new Exception(
28 | string.Format("An exception of type {0} was expected, but not thrown", typeof(T))
29 | );
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/ORM/ORMTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Linq;
5 | using Castle.DynamicLinqQueryBuilder.Tests.Database;
6 | using Microsoft.Data.Sqlite;
7 | using Microsoft.EntityFrameworkCore;
8 | using NUnit.Framework;
9 |
10 | namespace Castle.DynamicLinqQueryBuilder.Tests.ORM
11 | {
12 | [ExcludeFromCodeCoverage]
13 | [TestFixture]
14 | public class ORMTests: IDisposable
15 | {
16 | private readonly SqliteConnection _connection;
17 | private readonly DbContextOptions _contextOptions;
18 |
19 | public ORMTests()
20 | {
21 | _connection = new SqliteConnection("Filename=:memory:");
22 | _connection.Open();
23 |
24 | _contextOptions = new DbContextOptionsBuilder()
25 | .UseSqlite(_connection)
26 | .Options;
27 |
28 | // Create the schema and seed some data
29 | using var context = new StoreContext(_contextOptions);
30 |
31 | context.Database.EnsureCreated();
32 |
33 |
34 | var stores = new List()
35 | {
36 | new Store()
37 | {
38 | StoreId = Guid.NewGuid(),
39 | OpenDate = new DateTime(2020, 12, 18),
40 | StoreName = "Tractor Store",
41 | TotalRevenue = 200000000,
42 | Products = new List()
43 | {
44 | new Product()
45 | {
46 | ProductName = "Model 12 Tractor",
47 | ProductPrice = 75000
48 | },
49 | new Product()
50 | {
51 | ProductName = "Model 14 Tractor",
52 | ProductPrice = 122000
53 | },
54 | new Product()
55 | {
56 | ProductName = "Plow",
57 | ProductPrice = 1200
58 | }
59 | }
60 | },
61 | new Store()
62 | {
63 | StoreId = Guid.NewGuid(),
64 | OpenDate = new DateTime(2021, 12, 15),
65 | StoreName = "Tire Store",
66 | TotalRevenue = 150000000,
67 | Products = new List()
68 | {
69 | new Product()
70 | {
71 | ProductName = "Tractor Tire",
72 | ProductPrice = 12000
73 | },
74 | new Product()
75 | {
76 | ProductName = "Car Tire",
77 | ProductPrice = 120
78 | },
79 | new Product()
80 | {
81 | ProductName = "Cap",
82 | ProductPrice = 75
83 | }
84 | }
85 | }
86 | };
87 |
88 | context.AddRange(stores);
89 | context.SaveChanges();
90 |
91 | }
92 |
93 | StoreContext CreateContext() => new StoreContext(_contextOptions);
94 |
95 | public void Dispose() => _connection.Dispose();
96 |
97 | [Test]
98 | public void ContainsTractorTest()
99 | {
100 | var context = CreateContext();
101 |
102 | //expect 3 entries to match for an contains Tractor comparison
103 | var tractorFilter = new QueryBuilderFilterRule
104 | {
105 | Condition = "and",
106 | Rules = new List
107 | {
108 | new QueryBuilderFilterRule
109 | {
110 | Condition = "and",
111 | Field = "ProductName",
112 | Id = "ProductName",
113 | Input = "NA",
114 | Operator = "contains",
115 | Type = "string",
116 | Value = new[] { "Tractor" }
117 | }
118 | }
119 | };
120 |
121 | var tractorIdFilteredList = context.Products.BuildQuery(tractorFilter).ToList();
122 | Assert.IsTrue(tractorIdFilteredList != null);
123 | Assert.IsTrue(tractorIdFilteredList.Count == 3);
124 | }
125 |
126 | [Test]
127 | public void ContainsTractorDeepTest()
128 | {
129 | var context = CreateContext();
130 |
131 | //expect 3 entries to match for an contains Tractor comparison
132 | var tractorFilter = new QueryBuilderFilterRule
133 | {
134 | Condition = "and",
135 | Rules = new List
136 | {
137 | new QueryBuilderFilterRule
138 | {
139 | Condition = "and",
140 | Field = "Products.ProductName",
141 | Id = "Products.ProductName",
142 | Input = "NA",
143 | Operator = "contains",
144 | Type = "string",
145 | Value = new[] { "Tractor" }
146 | }
147 | }
148 | };
149 |
150 | var tractorIdFilteredList = context.Stores.BuildQuery(tractorFilter).ToList();
151 | Assert.IsTrue(tractorIdFilteredList != null);
152 | Assert.IsTrue(tractorIdFilteredList.Count == 2);
153 | }
154 |
155 | [Test]
156 | public void BeginsWithModelTest()
157 | {
158 | var context = CreateContext();
159 |
160 | //expect 2 entries to match for a begins with comparison
161 | var modelFilter = new QueryBuilderFilterRule
162 | {
163 | Condition = "and",
164 | Rules = new List
165 | {
166 | new QueryBuilderFilterRule
167 | {
168 | Condition = "and",
169 | Field = "ProductName",
170 | Id = "ProductName",
171 | Input = "NA",
172 | Operator = "begins_with",
173 | Type = "string",
174 | Value = new[] { "Model" }
175 | }
176 | }
177 | };
178 |
179 | var beginsFilteredList = context.Products.BuildQuery(modelFilter).ToList();
180 | Assert.IsTrue(beginsFilteredList != null);
181 | Assert.IsTrue(beginsFilteredList.Count == 2);
182 | }
183 |
184 | [Test]
185 | public void EqualsTireStoreTest()
186 | {
187 | var context = CreateContext();
188 |
189 | //expect 1 entry to match for an contains Tire Store comparison
190 | var storeFilter = new QueryBuilderFilterRule
191 | {
192 | Condition = "and",
193 | Rules = new List
194 | {
195 | new QueryBuilderFilterRule
196 | {
197 | Condition = "and",
198 | Field = "StoreName",
199 | Id = "StoreName",
200 | Input = "NA",
201 | Operator = "equal",
202 | Type = "string",
203 | Value = new[] { "Tire Store" }
204 | }
205 | }
206 | };
207 |
208 | var storeFilteredList = context.Stores.BuildQuery(storeFilter).ToList();
209 | Assert.IsTrue(storeFilteredList != null);
210 | Assert.IsTrue(storeFilteredList.Count == 1);
211 | }
212 |
213 |
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/ORM/ORMTestsMongo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Castle.DynamicLinqQueryBuilder.Tests.Database;
8 | using MongoDB.Bson;
9 | using MongoDB.Bson.Serialization.Conventions;
10 | using MongoDB.Driver;
11 | using NUnit.Framework;
12 |
13 | namespace Castle.DynamicLinqQueryBuilder.Tests.ORM {
14 | [ExcludeFromCodeCoverage]
15 | #if LOCALTEST
16 | [TestFixture]
17 | #endif
18 | public class ORMTestsMongo : IDisposable {
19 | private readonly IMongoDatabase _db;
20 | private readonly IMongoCollection _collection;
21 | private const string CollectionName = "restaurant";
22 |
23 | public ORMTestsMongo() {
24 | var connectionString = Environment.GetEnvironmentVariable("MONGODB_URI");
25 | if (connectionString == null) {
26 | Console.WriteLine(
27 | "You must set your 'MONGODB_URI' environmental variable. See\n\t https://www.mongodb.com/docs/drivers/go/current/usage-examples/#environment-variable");
28 | Environment.Exit(0);
29 | }
30 |
31 | var client = new MongoClient(connectionString);
32 | SetEnumConvention();
33 | _db = client.GetDatabase("DynamicLinqQueryBuilderTests");
34 | _db.DropCollection(CollectionName);
35 | _db.CreateCollection(CollectionName);
36 | _collection = _db.GetCollection(CollectionName);
37 |
38 |
39 | var restaurants = new List() {
40 | new Restaurant {
41 | Name = "My restaurant",
42 | RestaurantId = "Id",
43 | Status = Status.Open,
44 | Details = new Dictionary {
45 | ["items_count"] = 30,
46 | ["date_started"] = DateTime.Now - TimeSpan.FromDays(365),
47 | ["address"] = "street23"
48 | }
49 | },
50 | new Restaurant {
51 | Name = "My restaurant2",
52 | RestaurantId = "Id2",
53 | Status = Status.Closed,
54 | Details = new Dictionary {
55 | ["items_count"] = 40,
56 | ["date_started"] = DateTime.Now - TimeSpan.FromDays(20),
57 | ["address"] = "street33"
58 | }
59 | },
60 | new Restaurant {
61 | Name = "My restaurant3",
62 | RestaurantId = "Id3",
63 | Status = Status.Closed,
64 | Details = new Dictionary {
65 | ["not_any_other_field"] = "value"
66 | }
67 | }
68 | };
69 |
70 | _collection.InsertMany(restaurants);
71 | }
72 |
73 | private void SetEnumConvention() {
74 | var pack = new ConventionPack {
75 | new EnumRepresentationConvention(BsonType.String)
76 | };
77 |
78 | ConventionRegistry.Register("EnumStringConvention", pack, t => true);
79 | }
80 |
81 | public void Dispose() => _db.DropCollection(CollectionName);
82 |
83 | #if LOCALTEST
84 | [Test]
85 | #endif
86 | public async Task StringEndsWithTest() {
87 | var filter = new JsonNetFilterRule() {
88 | Condition = "and",
89 | Rules = new List {
90 | new JsonNetFilterRule {
91 | Field = "Name",
92 | Operator = "ends_with",
93 | Type = "string",
94 | Value = "2"
95 | }
96 | }
97 | };
98 | var expression = filter.BuildExpressionLambda(new BuildExpressionOptions(), out var _);
99 | var result = await _collection.Find(expression).ToListAsync();
100 | Assert.IsTrue(result.Count == 1);
101 | Assert.AreEqual(result.First().RestaurantId, "Id2");
102 | }
103 | #if LOCALTEST
104 | [Test]
105 | #endif
106 | public async Task EnumTest() {
107 | var filter = new JsonNetFilterRule() {
108 | Condition = "and",
109 | Rules = new List {
110 | new JsonNetFilterRule {
111 | Field = "Status",
112 | Operator = "equal",
113 | Type = "string",
114 | Value = "open"
115 | }
116 | }
117 | };
118 | var expression = filter.BuildExpressionLambda(new BuildExpressionOptions(), out var _);
119 | var result = await _collection.Find(expression).ToListAsync();
120 | Assert.IsTrue(result.Count == 1);
121 | Assert.AreEqual(result.First().RestaurantId, "Id");
122 |
123 | filter = new JsonNetFilterRule() {
124 | Condition = "and",
125 | Rules = new List {
126 | new JsonNetFilterRule {
127 | Field = "Status",
128 | Operator = "equal",
129 | Type = "string",
130 | Value = "open"
131 | }
132 | }
133 | };
134 |
135 | expression =
136 | filter.BuildExpressionLambda(
137 | new BuildExpressionOptions { StringCaseSensitiveComparison = true }, out var _);
138 | result = await _collection.Find(expression).ToListAsync();
139 | Assert.IsTrue(result.Count == 0);
140 | }
141 |
142 |
143 | #if LOCALTEST
144 | [Test]
145 | #endif
146 | public async Task DictionaryIntegerGreaterThenTest() {
147 | var filter = new JsonNetFilterRule() {
148 | Condition = "and",
149 | Rules = new List {
150 | new JsonNetFilterRule {
151 | Field = "Details.items_count",
152 | Operator = "greater",
153 | Type = "integer",
154 | Value = "35"
155 | }
156 | }
157 | };
158 | var expression = filter.BuildExpressionLambda(new BuildExpressionOptions(), out var _);
159 | var result = await _collection.Find(expression).ToListAsync();
160 | Assert.IsTrue(result.Count == 1);
161 | Assert.AreEqual(result.First().RestaurantId, "Id2");
162 | }
163 |
164 |
165 | #if LOCALTEST
166 | [Test]
167 | #endif
168 | public async Task DictionaryDateTimeGreaterThenTest() {
169 | var filter = new JsonNetFilterRule() {
170 | Condition = "and",
171 | Rules = new List {
172 | new JsonNetFilterRule {
173 | Field = "Details.date_started",
174 | Operator = "greater",
175 | Type = "datetime",
176 | Value = DateTime.Now - TimeSpan.FromDays(40)
177 | }
178 | }
179 | };
180 | var expression =
181 | filter.BuildExpressionLambda(
182 | new BuildExpressionOptions { CultureInfo = CultureInfo.CurrentCulture }, out var _);
183 | var result = await _collection.Find(expression).ToListAsync();
184 | Assert.IsTrue(result.Count == 1);
185 | Assert.AreEqual(result.First().RestaurantId, "Id2");
186 | }
187 |
188 | #if LOCALTEST
189 | [Test]
190 | #endif
191 | public async Task DictionaryStringEndsWithTest() {
192 | var filter = new JsonNetFilterRule() {
193 | Condition = "and",
194 | Rules = new List {
195 | new JsonNetFilterRule {
196 | Field = "Details.address",
197 | Operator = "ends_with",
198 | Type = "string",
199 | Value = "23"
200 | }
201 | }
202 | };
203 | var expression =
204 | filter.BuildExpressionLambda(
205 | new BuildExpressionOptions { CultureInfo = CultureInfo.CurrentCulture }, out var _);
206 | var result = await _collection.Find(expression).ToListAsync();
207 | Assert.IsTrue(result.Count == 1);
208 | Assert.AreEqual(result.First().RestaurantId, "Id");
209 | }
210 |
211 |
212 | #if LOCALTEST
213 | [Test]
214 | #endif
215 | public async Task DictionaryIsNullTest() {
216 | var filter = new JsonNetFilterRule() {
217 | Condition = "and",
218 | Rules = new List {
219 | new JsonNetFilterRule {
220 | Field = "Details.address",
221 | Operator = "is_null",
222 | Type = "string",
223 | }
224 | }
225 | };
226 | var expression =
227 | filter.BuildExpressionLambda(
228 | new BuildExpressionOptions { CultureInfo = CultureInfo.CurrentCulture }, out var _);
229 | var result = await _collection.Find(expression).ToListAsync();
230 | Assert.IsTrue(result.Count == 1);
231 | Assert.AreEqual(result.First().RestaurantId, "Id3");
232 | }
233 |
234 |
235 | #if LOCALTEST
236 | [Test]
237 | #endif
238 | public async Task DictionaryNotEqualTest() {
239 | var filter = new JsonNetFilterRule() {
240 | Condition = "and",
241 | Rules = new List {
242 | // mongo supports not_equal even if the the item does not exist in the dictionary
243 | // as oppose to inMemory filtering where it will throw KeyNotFound exception
244 | new JsonNetFilterRule {
245 | Field = "Details.address",
246 | Operator = "not_equal",
247 | Type = "string",
248 | Value = "a"
249 | }
250 | }
251 | };
252 | var expression =
253 | filter.BuildExpressionLambda(
254 | new BuildExpressionOptions
255 | { CultureInfo = CultureInfo.CurrentCulture, StringCaseSensitiveComparison = true }, out var _);
256 | var a = Builders.Filter.Where(expression);
257 | var b = a.Render(_collection.DocumentSerializer, _collection.Settings.SerializerRegistry).ToString();
258 | var result = await _collection.Find(expression).ToListAsync();
259 | Assert.IsTrue(result.Count == 3);
260 |
261 | // Verify that the expression is using ToString() on the value
262 | var filterDefinition = Builders.Filter.Where(expression);
263 | var mongoQuery = filterDefinition
264 | .Render(_collection.DocumentSerializer, _collection.Settings.SerializerRegistry).ToString();
265 | Assert.IsTrue(mongoQuery == @"{ ""$nor"" : [{ ""$and"" : [{ ""Details.address"" : { ""$ne"" : null } }, { ""$expr"" : { ""$eq"" : [{ ""$toString"" : ""$Details.address"" }, ""a""] } }] }] }");
266 | }
267 |
268 | #if LOCALTEST
269 | [Test]
270 | #endif
271 | public async Task DictionaryNotEqualTestAndRequireExplicitToStringConversionFlagFalse() {
272 | var filter = new JsonNetFilterRule() {
273 | Condition = "and",
274 | Rules = new List {
275 | // mongo supports not_equal even if the the item does not exist in the dictionary
276 | // as oppose to inMemory filtering where it will throw KeyNotFound exception
277 | new JsonNetFilterRule {
278 | Field = "Details.address",
279 | Operator = "not_equal",
280 | Type = "string",
281 | Value = "a"
282 | }
283 | }
284 | };
285 | var expression =
286 | filter.BuildExpressionLambda(
287 | new BuildExpressionOptions {
288 | CultureInfo = CultureInfo.CurrentCulture,
289 | StringCaseSensitiveComparison = true,
290 | RequireExplicitToStringConversion = false
291 | }, out var _);
292 |
293 | var result = await _collection.Find(expression).ToListAsync();
294 | Assert.IsTrue(result.Count == 3);
295 |
296 | // Verify that the expression is not using ToString() on the value
297 | var filterDefinition = Builders.Filter.Where(expression);
298 | var mongoQuery = filterDefinition
299 | .Render(_collection.DocumentSerializer, _collection.Settings.SerializerRegistry).ToString();
300 | Assert.IsTrue(mongoQuery == @"{ ""$nor"" : [{ ""$and"" : [{ ""Details.address"" : { ""$ne"" : null } }, { ""Details.address"" : ""a"" }] }] }");
301 | }
302 |
303 | #if LOCALTEST
304 | [Test]
305 | #endif
306 | public async Task DictionaryNotContainsTest() {
307 | var filter = new JsonNetFilterRule() {
308 | Condition = "and",
309 | Rules = new List {
310 | // mongo supports not_equal even if the the item does not exist in the dictionary
311 | // as oppose to inMemory filtering where it will throw KeyNotFound exception
312 | new JsonNetFilterRule {
313 | Field = "Details",
314 | Operator = "not_contains",
315 | Type = "string",
316 | Value = "address"
317 | }
318 | }
319 | };
320 | var expression =
321 | filter.BuildExpressionLambda(
322 | new BuildExpressionOptions { CultureInfo = CultureInfo.CurrentCulture }, out var _);
323 | var result = await _collection.Find(expression).ToListAsync();
324 | Assert.IsTrue(result.Count == 1);
325 | }
326 | }
327 | }
328 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.Tests/ORM/ORMTestsSQLServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Linq;
5 | using System.Net.Mime;
6 | using Castle.DynamicLinqQueryBuilder.Tests.Database;
7 | using Microsoft.Data.SqlClient;
8 | using Microsoft.Data.Sqlite;
9 | using Microsoft.EntityFrameworkCore;
10 | using NUnit.Framework;
11 |
12 | namespace Castle.DynamicLinqQueryBuilder.Tests.ORM
13 | {
14 | [ExcludeFromCodeCoverage]
15 | #if LOCALTEST
16 | [TestFixture]
17 | #endif
18 | public class ORMTestsSQLServer: IDisposable
19 | {
20 | private readonly SqlConnection _connection;
21 | private readonly DbContextOptions _contextOptions;
22 |
23 | public ORMTestsSQLServer()
24 | {
25 | _connection = new SqlConnection("Server=localhost;Database=DynamicLinqQueryBuilderTests;User ID=sa;Password=Password123;Connection Timeout=30;TrustServerCertificate=True");
26 | _connection.Open();
27 |
28 | _contextOptions = new DbContextOptionsBuilder()
29 | .UseSqlServer(_connection)
30 | .Options;
31 |
32 | // Create the schema and seed some data
33 | using var context = new StoreContext(_contextOptions);
34 |
35 | context.Database.EnsureCreated();
36 |
37 | var storesOld = context.Stores.ToList();
38 |
39 | foreach (var store in storesOld)
40 | {
41 | context.Stores.Remove(store);
42 | }
43 |
44 | context.SaveChanges();
45 |
46 |
47 |
48 |
49 | var stores = new List()
50 | {
51 | new Store()
52 | {
53 | StoreId = Guid.NewGuid(),
54 | OpenDate = new DateTime(2020, 12, 18),
55 | StoreName = "Tractor Store",
56 | StoreOwner = new StoreOwner()
57 | {
58 | StoreOwnerName = "Henry Rollins"
59 | },
60 | TotalRevenue = 200000000,
61 | Products = new List()
62 | {
63 | new Product()
64 | {
65 | ProductName = "Model 12 Tractor",
66 | ProductPrice = 75000
67 | },
68 | new Product()
69 | {
70 | ProductName = "Model 14 Tractor",
71 | ProductPrice = 122000
72 | },
73 | new Product()
74 | {
75 | ProductName = "Plow",
76 | ProductPrice = 1200
77 | }
78 | }
79 | },
80 | new Store()
81 | {
82 | StoreId = Guid.NewGuid(),
83 | OpenDate = new DateTime(2021, 12, 15),
84 | StoreName = "Tire Store",
85 | StoreOwner = new StoreOwner()
86 | {
87 | StoreOwnerName = "Lucas Franken"
88 | },
89 | TotalRevenue = 150000000,
90 | Products = new List()
91 | {
92 | new Product()
93 | {
94 | ProductName = "Tractor Tire",
95 | ProductPrice = 12000
96 | },
97 | new Product()
98 | {
99 | ProductName = "Car Tire",
100 | ProductPrice = 120
101 | },
102 | new Product()
103 | {
104 | ProductName = "Cap",
105 | ProductPrice = 75
106 | }
107 | }
108 | }
109 | };
110 |
111 | context.AddRange(stores);
112 | context.SaveChanges();
113 |
114 | }
115 |
116 | StoreContext CreateContext() => new StoreContext(_contextOptions);
117 |
118 | public void Dispose() => _connection.Dispose();
119 |
120 | #if LOCALTEST
121 | [Test]
122 | #endif
123 | public void ContainsTractorTest()
124 | {
125 | var context = CreateContext();
126 |
127 | //expect 3 entries to match for an contains Tractor comparison
128 | var tractorFilter = new QueryBuilderFilterRule
129 | {
130 | Condition = "and",
131 | Rules = new List
132 | {
133 | new QueryBuilderFilterRule
134 | {
135 | Condition = "and",
136 | Field = "ProductName",
137 | Id = "ProductName",
138 | Input = "NA",
139 | Operator = "contains",
140 | Type = "string",
141 | Value = new[] { "Tractor" }
142 | }
143 | }
144 | };
145 |
146 | var tractorIdFilteredList = context.Products.BuildQuery(tractorFilter).ToList();
147 | Assert.IsTrue(tractorIdFilteredList != null);
148 | Assert.IsTrue(tractorIdFilteredList.Count == 3);
149 | }
150 |
151 | #if LOCALTEST
152 | [Test]
153 | #endif
154 | public void ContainsTractorDeepTest()
155 | {
156 | var context = CreateContext();
157 |
158 | //expect 3 entries to match for an contains Tractor comparison
159 | var tractorFilter = new QueryBuilderFilterRule
160 | {
161 | Condition = "and",
162 | Rules = new List
163 | {
164 | new QueryBuilderFilterRule
165 | {
166 | Condition = "and",
167 | Field = "StoreOwner.StoreOwnerName",
168 | Id = "StoreOwner.StoreOwnerName",
169 | Input = "NA",
170 | Operator = "in",
171 | Type = "string",
172 | Value = new[] { "Henry Rollins", "Lucas Franken" }
173 | }
174 | }
175 | };
176 | var query = string.Empty;
177 | var tractorIdFilteredList = context.Stores.Select(p => new StoreDto()
178 | {
179 | StoreId = p.StoreId,
180 | StoreOwner = new StoreOwnerDto()
181 | {
182 | StoreOwnerName = p.StoreOwner.StoreOwnerName
183 | }
184 | }).BuildQuery(tractorFilter, new BuildExpressionOptions()
185 | {
186 | NullCheckNestedCLRObjects = false
187 | }).ToList();
188 | Assert.IsTrue(tractorIdFilteredList != null);
189 | Assert.IsTrue(tractorIdFilteredList.Count == 2);
190 | }
191 | [ExcludeFromCodeCoverage]
192 | public class StoreDto
193 | {
194 | public Guid StoreId { get; set; }
195 | public StoreOwnerDto StoreOwner { get; set; }
196 | }
197 | [ExcludeFromCodeCoverage]
198 | public class StoreOwnerDto
199 | {
200 | public string StoreOwnerName { get; set; }
201 | }
202 |
203 | #if LOCALTEST
204 | [Test]
205 | #endif
206 | public void BeginsWithModelTest()
207 | {
208 | var context = CreateContext();
209 |
210 | //expect 2 entries to match for a begins with comparison
211 | var modelFilter = new QueryBuilderFilterRule
212 | {
213 | Condition = "and",
214 | Rules = new List
215 | {
216 | new QueryBuilderFilterRule
217 | {
218 | Condition = "and",
219 | Field = "ProductName",
220 | Id = "ProductName",
221 | Input = "NA",
222 | Operator = "begins_with",
223 | Type = "string",
224 | Value = new[] { "Model" }
225 | }
226 | }
227 | };
228 |
229 | var beginsFilteredList = context.Products.BuildQuery(modelFilter).ToList();
230 | Assert.IsTrue(beginsFilteredList != null);
231 | Assert.IsTrue(beginsFilteredList.Count == 2);
232 | }
233 |
234 | #if LOCALTEST
235 | [Test]
236 | #endif
237 | public void EqualsTireStoreTest()
238 | {
239 | var context = CreateContext();
240 |
241 | //expect 1 entry to match for an contains Tire Store comparison
242 | var storeFilter = new QueryBuilderFilterRule
243 | {
244 | Condition = "and",
245 | Rules = new List
246 | {
247 | new QueryBuilderFilterRule
248 | {
249 | Condition = "and",
250 | Field = "StoreName",
251 | Id = "StoreName",
252 | Input = "NA",
253 | Operator = "equal",
254 | Type = "string",
255 | Value = new[] { "Tire Store" }
256 | }
257 | }
258 | };
259 |
260 | var storeFilteredList = context.Stores.BuildQuery(storeFilter).ToList();
261 | Assert.IsTrue(storeFilteredList != null);
262 | Assert.IsTrue(storeFilteredList.Count == 1);
263 | }
264 |
265 |
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32210.238
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.DynamicLinqQueryBuilder", "Castle.DynamicLinqQueryBuilder\Castle.DynamicLinqQueryBuilder.csproj", "{C73EA60C-7046-4665-8A79-0E2AA85C43EC}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.DynamicLinqQueryBuilder.SystemTextJson", "Castle.DynamicLinqQueryBuilder.SystemTextJson\Castle.DynamicLinqQueryBuilder.SystemTextJson.csproj", "{22861CF7-71BB-44AF-9630-AC3A59F36838}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Castle.DynamicLinqQueryBuilder.Tests", "Castle.DynamicLinqQueryBuilder.Tests\Castle.DynamicLinqQueryBuilder.Tests.csproj", "{09AFE101-7579-423E-B271-1AEFC76DDCD7}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | LocalTest|Any CPU = LocalTest|Any CPU
16 | Release|Any CPU = Release|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}.LocalTest|Any CPU.ActiveCfg = LocalTest|Any CPU
22 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}.LocalTest|Any CPU.Build.0 = LocalTest|Any CPU
23 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {22861CF7-71BB-44AF-9630-AC3A59F36838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {22861CF7-71BB-44AF-9630-AC3A59F36838}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {22861CF7-71BB-44AF-9630-AC3A59F36838}.LocalTest|Any CPU.ActiveCfg = LocalTest|Any CPU
28 | {22861CF7-71BB-44AF-9630-AC3A59F36838}.LocalTest|Any CPU.Build.0 = LocalTest|Any CPU
29 | {22861CF7-71BB-44AF-9630-AC3A59F36838}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {22861CF7-71BB-44AF-9630-AC3A59F36838}.Release|Any CPU.Build.0 = Release|Any CPU
31 | {09AFE101-7579-423E-B271-1AEFC76DDCD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {09AFE101-7579-423E-B271-1AEFC76DDCD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {09AFE101-7579-423E-B271-1AEFC76DDCD7}.LocalTest|Any CPU.ActiveCfg = LocalTest|Any CPU
34 | {09AFE101-7579-423E-B271-1AEFC76DDCD7}.LocalTest|Any CPU.Build.0 = LocalTest|Any CPU
35 | {09AFE101-7579-423E-B271-1AEFC76DDCD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {09AFE101-7579-423E-B271-1AEFC76DDCD7}.Release|Any CPU.Build.0 = Release|Any CPU
37 | EndGlobalSection
38 | GlobalSection(SolutionProperties) = preSolution
39 | HideSolutionNode = FALSE
40 | EndGlobalSection
41 | GlobalSection(ExtensibilityGlobals) = postSolution
42 | SolutionGuid = {D6D73EB7-5984-40FA-848C-D5DBE5326AB9}
43 | EndGlobalSection
44 | EndGlobal
45 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder.v3.ncrunchsolution:
--------------------------------------------------------------------------------
1 |
2 |
3 | False
4 | True
5 |
6 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/BuildExpressionOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 |
5 | namespace Castle.DynamicLinqQueryBuilder
6 | {
7 | ///
8 | /// Options to use when building expressions
9 | ///
10 | public class BuildExpressionOptions
11 | {
12 | ///
13 | /// The to use when converting string representations (default InvariantCulture).
14 | ///
15 | public CultureInfo CultureInfo { get; set; } = CultureInfo.InvariantCulture;
16 |
17 | ///
18 | /// Whether types should be parsed as UTC.
19 | ///
20 | public bool ParseDatesAsUtc { get; set; }
21 |
22 | ///
23 | /// Whether or not to use indexed property
24 | ///
25 | public bool UseIndexedProperty { get; set; }
26 |
27 | ///
28 | /// The name of indexable property to use.
29 | ///
30 | public string IndexedPropertyName { get; set; }
31 |
32 | ///
33 | /// Custom operators
34 | ///
35 | public IEnumerable Operators { get; set; }
36 |
37 | ///
38 | /// Flag to null check CLR objects in nested queries. May Cause ORM queries to fail.
39 | ///
40 | public bool NullCheckNestedCLRObjects { get; set; } = false;
41 |
42 | ///
43 | /// Indicates whether string comparisons are case sensitive or not, utilizing .ToLower() method
44 | ///
45 | public bool StringCaseSensitiveComparison { get; set; } = false;
46 |
47 | ///
48 | /// Indicates whether to require explicit ToString() conversion for non-string types
49 | ///
50 | public bool RequireExplicitToStringConversion { get; set; } = true;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/Castle.DynamicLinqQueryBuilder.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {C73EA60C-7046-4665-8A79-0E2AA85C43EC}
7 | Library
8 | Properties
9 | Castle.DynamicLinqQueryBuilder
10 | Castle.DynamicLinqQueryBuilder
11 | netstandard2.0;net6;net45;net8
12 | 512
13 |
14 | true
15 | 1.3.4
16 | 1.3.4.0
17 | 1.3.4.0
18 | Grant Hamm
19 | N/A
20 | Dynamic Linq Query Builder
21 | A simple dynamic expression-tree query builder. You pass it a nested collection of filters for an object, and it materializes a query capable of acting as the filter to an arbitrary collection.
22 | This library is licensed MIT, in the public domain
23 | MIT
24 | https://github.com/tghamm/dynamic-linq-query-builder/
25 | https://github.com/tghamm/dynamic-linq-query-builder/
26 | Git
27 | jquery-query-builder generic query generator linq javascript
28 | Minor Enhancements
29 | latest
30 | True
31 | README.md
32 | true
33 | true
34 | snupkg
35 | Debug;Release;LocalTest
36 |
37 |
38 | true
39 | full
40 | false
41 | bin\Debug\
42 | DEBUG;TRACE
43 | prompt
44 | 4
45 | bin\Debug\Castle.DynamicLinqQueryBuilder.xml
46 |
47 |
48 | true
49 | full
50 | false
51 | bin\Debug\
52 | DEBUG;TRACE
53 | prompt
54 | 4
55 | bin\Debug\Castle.DynamicLinqQueryBuilder.xml
56 |
57 |
58 | pdbonly
59 | true
60 | bin\Release\
61 | TRACE
62 | prompt
63 | 4
64 | bin\Release\Castle.DynamicLinqQueryBuilder.xml
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 | True
91 | \
92 |
93 |
94 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/ColumnBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Runtime.Serialization;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace Castle.DynamicLinqQueryBuilder
8 | {
9 | ///
10 | /// Class to assist with building column definitions for the jQuery Query Builder
11 | ///
12 | public static class ColumnBuilder
13 | {
14 | ///
15 | /// Gets the default column definitions for a given type.
16 | ///
17 | /// Type of the data.
18 | /// if set to true [camel case].
19 | ///
20 | public static List GetDefaultColumnDefinitionsForType(this Type dataType, bool camelCase = false)
21 | {
22 | List itemBankColumnDefinitions = new List();
23 |
24 | var id = 1;
25 | foreach (var prop in dataType.GetProperties())
26 | {
27 | if (prop.GetCustomAttribute(typeof(IgnoreDataMemberAttribute)) != null) continue;
28 |
29 | var name = camelCase ? prop.Name.ToCamelCase() : prop.Name;
30 |
31 | var title = prop.Name.ToFriendlySpacedString();
32 |
33 | var type = string.Empty;
34 |
35 | if ((prop.PropertyType == typeof(double)) || (prop.PropertyType == typeof(double?))
36 | || (prop.PropertyType == typeof(float)) || (prop.PropertyType == typeof(float?))
37 | || (prop.PropertyType == typeof(decimal)) || (prop.PropertyType == typeof(decimal?)))
38 | {
39 | type = "double";
40 | }
41 | else if ((prop.PropertyType == typeof(int)) || (prop.PropertyType == typeof(int?))
42 | || (prop.PropertyType == typeof(long)) || (prop.PropertyType == typeof(long?)))
43 | {
44 | type = "integer";
45 | }
46 | else if ((prop.PropertyType == typeof(DateTime)) || (prop.PropertyType == typeof(DateTime?)))
47 | {
48 | type = "date";
49 | }
50 | else if ((prop.PropertyType == typeof(string)))
51 | {
52 | type = "string";
53 | }
54 | else if ((prop.PropertyType == typeof(bool)) || (prop.PropertyType == typeof(bool?)))
55 | {
56 | type = "boolean";
57 | }
58 |
59 | switch (type)
60 | {
61 | case "double":
62 | itemBankColumnDefinitions.Add(new ColumnDefinition()
63 | {
64 | Label = title,
65 | Field = name,
66 | Type = type,
67 | Id = id.ToString()
68 | });
69 | break;
70 | case "integer":
71 | itemBankColumnDefinitions.Add(new ColumnDefinition()
72 | {
73 | Label = title,
74 | Field = name,
75 | Type = type,
76 | Id = id.ToString()
77 | });
78 | break;
79 | case "string":
80 | itemBankColumnDefinitions.Add(new ColumnDefinition()
81 | {
82 | Label = title,
83 | Field = name,
84 | Type = type,
85 | Id = id.ToString()
86 | });
87 | break;
88 | case "date":
89 | itemBankColumnDefinitions.Add(new ColumnDefinition()
90 | {
91 | Label = title,
92 | Field = name,
93 | Type = type,
94 | Id = id.ToString()
95 | });
96 | break;
97 | case "boolean":
98 | itemBankColumnDefinitions.Add(new ColumnDefinition()
99 | {
100 | Label = title,
101 | Field = name,
102 | Type = type,
103 | Id = id.ToString()
104 | });
105 | break;
106 | }
107 |
108 | id++;
109 | }
110 | return itemBankColumnDefinitions;
111 | }
112 |
113 | ///
114 | /// Camel cases a string.
115 | ///
116 | /// The input.
117 | ///
118 | public static string ToCamelCase(this string input)
119 | {
120 | var s = input;
121 | if (!char.IsUpper(s[0])) return s;
122 |
123 | var cArr = s.ToCharArray();
124 | for (var i = 0; i < cArr.Length; i++)
125 | {
126 | if (i > 0 && i + 1 < cArr.Length && !char.IsUpper(cArr[i + 1])) break;
127 | cArr[i] = char.ToLowerInvariant(cArr[i]);
128 | }
129 | return new string(cArr);
130 | }
131 |
132 | ///
133 | /// Pretty-prints a property name.
134 | ///
135 | /// The input.
136 | ///
137 | public static string ToFriendlySpacedString(this string input)
138 | {
139 | var r = new Regex(@"
140 | (?<=[A-Z])(?=[A-Z][a-z]) |
141 | (?<=[^A-Z])(?=[A-Z]) |
142 | (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
143 |
144 |
145 | var res = r.Replace(input, " ");
146 |
147 | return res;
148 | }
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/ColumnDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.Runtime.Serialization;
5 |
6 | namespace Castle.DynamicLinqQueryBuilder
7 | {
8 | ///
9 | /// Defines the columns to be filtered against in the UI component of jQuery Query Builder
10 | ///
11 | [ExcludeFromCodeCoverage]
12 | [DataContract]
13 | public class ColumnDefinition
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | public ColumnDefinition()
19 | {
20 | PrettyOutputTransformer = o => o;
21 | }
22 | ///
23 | /// Gets or sets the label.
24 | ///
25 | ///
26 | /// The label.
27 | ///
28 | [DataMember]
29 | public string Label { get; set; }
30 | ///
31 | /// Gets or sets the field.
32 | ///
33 | ///
34 | /// The field.
35 | ///
36 | [DataMember]
37 | public string Field { get; set; }
38 | ///
39 | /// Gets or sets the type.
40 | ///
41 | ///
42 | /// The type.
43 | ///
44 | [DataMember]
45 | public string Type { get; set; }
46 | ///
47 | /// Gets or sets the input.
48 | ///
49 | ///
50 | /// The input.
51 | ///
52 | [DataMember]
53 | public string Input { get; set; }
54 | ///
55 | /// Gets or sets the multiple.
56 | ///
57 | ///
58 | /// The multiple.
59 | ///
60 | [DataMember]
61 | public bool? Multiple { get; set; }
62 | ///
63 | /// Gets or sets the values.
64 | ///
65 | ///
66 | /// The values.
67 | ///
68 | [DataMember]
69 | public object Values { get; set; }
70 | ///
71 | /// Gets or sets the operators.
72 | ///
73 | ///
74 | /// The operators.
75 | ///
76 | [DataMember]
77 | public List Operators { get; set; }
78 | ///
79 | /// Gets or sets the template.
80 | ///
81 | ///
82 | /// The template.
83 | ///
84 | [DataMember]
85 | public string Template { get; set; }
86 | ///
87 | /// Gets or sets the item bank not filterable.
88 | ///
89 | ///
90 | /// The item bank not filterable.
91 | ///
92 | [DataMember]
93 | public bool? ItemBankNotFilterable { get; set; }
94 | ///
95 | /// Gets or sets the item bank not column.
96 | ///
97 | ///
98 | /// The item bank not column.
99 | ///
100 | [DataMember]
101 | public bool? ItemBankNotColumn { get; set; }
102 | ///
103 | /// Gets or sets the pretty output transformer.
104 | ///
105 | ///
106 | /// The pretty output transformer.
107 | ///
108 | [IgnoreDataMember]
109 | public Func PrettyOutputTransformer { get; set; }
110 |
111 | ///
112 | /// Gets or sets the identifier.
113 | ///
114 | ///
115 | /// The identifier.
116 | ///
117 | [DataMember]
118 | public string Id { get; set; }
119 |
120 | ///
121 | /// Gets or sets the plugin to use.
122 | ///
123 | ///
124 | /// The plugin.
125 | ///
126 | [DataMember]
127 | public string Plugin { get; set; }
128 |
129 | ///
130 | /// Gets or sets the plugin configuration.
131 | ///
132 | ///
133 | /// The object defining the plugin configuration.
134 | ///
135 | [DataMember]
136 | public object Plugin_config { get; set; }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/FilterRule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 |
5 | namespace Castle.DynamicLinqQueryBuilder
6 | {
7 | ///
8 | /// This class is used to define a hierarchical filter for a given collection.
9 | ///
10 | [ExcludeFromCodeCoverage]
11 | [Obsolete("This type is deprecated in favor of QueryBuilderFilterRule or JsonNetFilterRule - see Wiki for more")]
12 | public class FilterRule : IFilterRule
13 | {
14 | ///
15 | /// Condition - acceptable values are "and" and "or".
16 | ///
17 | ///
18 | /// The condition.
19 | ///
20 | public string Condition { get; set; }
21 | ///
22 | /// The name of the field that the filter applies to.
23 | ///
24 | ///
25 | /// The field.
26 | ///
27 | public string Field { get; set; }
28 | ///
29 | /// Gets or sets the identifier.
30 | ///
31 | ///
32 | /// The identifier.
33 | ///
34 | public string Id { get; set; }
35 | ///
36 | /// Gets or sets the input.
37 | ///
38 | ///
39 | /// The input.
40 | ///
41 | public string Input { get; set; }
42 | ///
43 | /// Gets or sets the operator.
44 | ///
45 | ///
46 | /// The operator.
47 | ///
48 | public string Operator { get; set; }
49 | ///
50 | /// Gets or sets nested filter rules.
51 | ///
52 | ///
53 | /// The rules.
54 | ///
55 | public List Rules { get; set; }
56 | ///
57 | /// Gets or sets the type. Supported values are "integer", "double", "string", "date", "datetime", "guid", and "boolean".
58 | ///
59 | ///
60 | /// The type.
61 | ///
62 | public string Type { get; set; }
63 | ///
64 | /// Gets or sets the value of the filter.
65 | ///
66 | ///
67 | /// The value.
68 | ///
69 | public string Value { get; set; }
70 |
71 | IEnumerable IFilterRule.Rules => Rules;
72 | object IFilterRule.Value => Value;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/IFilterOperator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq.Expressions;
4 | using System.Text;
5 |
6 | namespace Castle.DynamicLinqQueryBuilder
7 | {
8 | ///
9 | /// This interface is used to define a custom filter operator
10 | ///
11 | public interface IFilterOperator
12 | {
13 | ///
14 | /// Custom operator name
15 | ///
16 | string Operator { get; }
17 |
18 | ///
19 | /// Get Custom Expression
20 | ///
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/IFilterRule.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Castle.DynamicLinqQueryBuilder
4 | {
5 | ///
6 | /// This interface is used to define a hierarchical filter for a given collection.
7 | ///
8 | public interface IFilterRule
9 | {
10 | ///
11 | /// Condition - acceptable values are "and" and "or".
12 | ///
13 | ///
14 | /// The condition.
15 | ///
16 | string Condition { get; }
17 | ///
18 | /// The name of the field that the filter applies to.
19 | ///
20 | ///
21 | /// The field.
22 | ///
23 | string Field { get; }
24 | ///
25 | /// Gets or sets the identifier.
26 | ///
27 | ///
28 | /// The identifier.
29 | ///
30 | string Id { get; }
31 | ///
32 | /// Gets or sets the input.
33 | ///
34 | ///
35 | /// The input.
36 | ///
37 | string Input { get; }
38 | ///
39 | /// Gets or sets the operator.
40 | ///
41 | ///
42 | /// The operator.
43 | ///
44 | string Operator { get; }
45 | ///
46 | /// Gets or sets nested filter rules.
47 | ///
48 | ///
49 | /// The rules.
50 | ///
51 | IEnumerable Rules { get; }
52 | ///
53 | /// Gets or sets the type. Supported values are "integer", "double", "string", "date", "datetime", and "boolean".
54 | ///
55 | ///
56 | /// The type.
57 | ///
58 | string Type { get; }
59 | ///
60 | /// Gets or sets the value of the filter.
61 | ///
62 | ///
63 | /// The value.
64 | ///
65 | object Value { get; }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/JsonNetFilterRule.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace Castle.DynamicLinqQueryBuilder
5 | {
6 | ///
7 | /// This class is used to define a hierarchical filter for a given collection. This type can be serialized/deserialized by JSON.NET without needing to modify the data structure from QueryBuilder.
8 | ///
9 | [ExcludeFromCodeCoverage]
10 | public class JsonNetFilterRule : IFilterRule
11 | {
12 | ///
13 | /// Condition - acceptable values are "and" and "or".
14 | ///
15 | ///
16 | /// The condition.
17 | ///
18 | public string Condition { get; set; }
19 | ///
20 | /// The name of the field that the filter applies to.
21 | ///
22 | ///
23 | /// The field.
24 | ///
25 | public string Field { get; set; }
26 | ///
27 | /// Gets or sets the identifier.
28 | ///
29 | ///
30 | /// The identifier.
31 | ///
32 | public string Id { get; set; }
33 | ///
34 | /// Gets or sets the input.
35 | ///
36 | ///
37 | /// The input.
38 | ///
39 | public string Input { get; set; }
40 | ///
41 | /// Gets or sets the operator.
42 | ///
43 | ///
44 | /// The operator.
45 | ///
46 | public string Operator { get; set; }
47 | ///
48 | /// Gets or sets nested filter rules.
49 | ///
50 | ///
51 | /// The rules.
52 | ///
53 | public List Rules { get; set; }
54 | ///
55 | /// Gets or sets the type. Supported values are "integer", "double", "string", "date", "datetime", "guid", and "boolean".
56 | ///
57 | ///
58 | /// The type.
59 | ///
60 | public string Type { get; set; }
61 | ///
62 | /// Gets or sets the value of the filter.
63 | ///
64 | ///
65 | /// The value.
66 | ///
67 | public object Value { get; set; }
68 |
69 | IEnumerable IFilterRule.Rules => Rules;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/QueryBuilderFilterRule.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace Castle.DynamicLinqQueryBuilder
5 | {
6 | ///
7 | /// This class is used to define a hierarchical filter for a given collection. This type assumes the data structure from QueryBuilder will be convert all Value instances to an array in JS.
8 | ///
9 | [ExcludeFromCodeCoverage]
10 | public class QueryBuilderFilterRule : IFilterRule
11 | {
12 | ///
13 | /// Condition - acceptable values are "and" and "or".
14 | ///
15 | ///
16 | /// The condition.
17 | ///
18 | public string Condition { get; set; }
19 | ///
20 | /// The name of the field that the filter applies to.
21 | ///
22 | ///
23 | /// The field.
24 | ///
25 | public string Field { get; set; }
26 | ///
27 | /// Gets or sets the identifier.
28 | ///
29 | ///
30 | /// The identifier.
31 | ///
32 | public string Id { get; set; }
33 | ///
34 | /// Gets or sets the input.
35 | ///
36 | ///
37 | /// The input.
38 | ///
39 | public string Input { get; set; }
40 | ///
41 | /// Gets or sets the operator.
42 | ///
43 | ///
44 | /// The operator.
45 | ///
46 | public string Operator { get; set; }
47 | ///
48 | /// Gets or sets nested filter rules.
49 | ///
50 | ///
51 | /// The rules.
52 | ///
53 | public List Rules { get; set; }
54 | ///
55 | /// Gets or sets the type. Supported values are "integer", "double", "string", "date", "datetime", "guid", and "boolean".
56 | ///
57 | ///
58 | /// The type.
59 | ///
60 | public string Type { get; set; }
61 | ///
62 | /// Gets or sets the value of the filter.
63 | ///
64 | ///
65 | /// The value.
66 | ///
67 | public string[] Value { get; set; }
68 |
69 | IEnumerable IFilterRule.Rules => Rules;
70 | object IFilterRule.Value => Value;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Castle.DynamicLinqQueryBuilder/ReflectionHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace Castle.DynamicLinqQueryBuilder
7 | {
8 | public static class ReflectionHelpers
9 | {
10 | public static MethodInfo SelectMethod;
11 | public static MethodInfo WhereMethod;
12 | public static MethodInfo ContainsMethod;
13 | public static MethodInfo ToListMethod;
14 |
15 | static ReflectionHelpers()
16 | {
17 | SelectMethod = GetExtensionMethod(typeof(Enumerable).Assembly, "Select");
18 | WhereMethod = GetExtensionMethod(typeof(Enumerable).Assembly, "Where");
19 | ContainsMethod = GetExtensionMethod(typeof(Enumerable).Assembly, "Contains");
20 | ToListMethod = GetExtensionMethod(typeof(Enumerable).Assembly, "ToList");
21 | }
22 |
23 | public static IEnumerable GetExtensionMethods(Assembly extensionsAssembly)
24 | => from t in extensionsAssembly.GetTypes()
25 | where !t.IsGenericType && !t.IsNested
26 | from m in t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
27 | where m.IsDefined(typeof(System.Runtime.CompilerServices.ExtensionAttribute), false)
28 | //where m.GetParameters()[0].ParameterType == type
29 | select m;
30 |
31 | public static MethodInfo GetExtensionMethod(Assembly extensionsAssembly, string name)
32 | => GetExtensionMethods(extensionsAssembly).FirstOrDefault(m => m.Name == name);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2023 Grant Hamm
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dynamic Linq Query Builder
2 | [](https://github.com/tghamm/dynamic-linq-query-builder/actions/workflows/dotnet.yml) [](https://coveralls.io/github/tghamm/dynamic-linq-query-builder?branch=master) [](https://www.nuget.org/packages/Castle.DynamicLinqQueryBuilder/)
3 |
4 | `dynamic-linq-query-builder` is a small library that allows any `.Net` framework class collection to be filtered dynamically at runtime.
5 |
6 | Features (v1.3.4)
7 | --
8 | * Generates an `IQueryable` from any collection and filter combination
9 | * Capable of complex, grouped queries against as many fields as you want
10 | * Supports nested objects and collections via dot notation
11 | * Supports ORMs like `EF6`, `EFCore`, and `MongoDB Client >=2.19`
12 | * Supports a number of operators for each type
13 | * in
14 | * not in
15 | * equal
16 | * not equal
17 | * between
18 | * not between
19 | * less
20 | * less or equal
21 | * greater
22 | * greater or equal
23 | * begins with
24 | * not begins with
25 | * contains
26 | * not contains
27 | * ends with
28 | * not ends with
29 | * is empty
30 | * is not empty
31 | * is null
32 | * is not null
33 | * custom operators via interface and options
34 | * Compatible with [jQuery QueryBuilder](https://querybuilder.js.org) (see samples for an example)
35 |
36 | * Targets .NET 4.5, .NET Standard 2.0, .NET 6, and .NET 8
37 |
38 | Installation
39 | --
40 | `dynamic-linq-query-builder` can be installed via the nuget UI (as Castle.DynamicLinqQueryBuilder), or via the nuget package manager console:
41 | ```
42 | PM> Install-Package Castle.DynamicLinqQueryBuilder
43 | ```
44 | To Install the System.Text.Json extension:
45 | --
46 | `dynamic-linq-query-builder-system-text-json` can be installed via the nuget UI (as Castle.DynamicLinqQueryBuilder.SystemTextJson), or via the nuget package manager console:
47 | ```
48 | PM> Install-Package Castle.DynamicLinqQueryBuilder.SystemTextJson
49 | ```
50 |
51 | Getting Started
52 | --
53 | The easiest way to get started is to install the NuGet package and take a look at the MVC sample application included in the source code. It contains a working example of both `dynamic-linq-query-builder` and `jQuery-QueryBuilder`.
54 |
55 | Additionally, see the [Wiki](https://github.com/tghamm/dynamic-linq-query-builder/wiki)
56 |
57 | Contributions
58 | --
59 | Contributions and pull requests are welcome with associated unit tests.
60 |
--------------------------------------------------------------------------------