1- using System . Collections ;
1+ using System ;
2+ using System . Collections ;
23using System . Collections . Generic ;
3- using System . ComponentModel ;
4+ using System . Globalization ;
5+ using System . Linq ;
6+ using System . Linq . Expressions ;
47using Newtonsoft . Json ;
58using Postgrest . Exceptions ;
69using Postgrest . Interfaces ;
10+ using Postgrest . Linq ;
711using static Postgrest . Constants ;
812
913namespace Postgrest
1014{
15+ /// <summary>
16+ /// Allow for the expression of a query filter with linq expressions.
17+ /// </summary>
18+ /// <typeparam name="TModel"></typeparam>
19+ /// <typeparam name="TCriterion"></typeparam>
20+ public class QueryFilter < TModel , TCriterion > : IPostgrestQueryFilter
21+ {
22+ /// <inheritdoc />
23+ public object ? Criteria { get ; }
24+
25+ /// <inheritdoc />
26+ public Operator Op { get ; }
27+
28+ /// <inheritdoc />
29+ public string ? Property { get ; }
30+
31+ /// <summary>
32+ /// Allows the creation of a Query Filter using a LINQ expression.
33+ /// </summary>
34+ /// <param name="predicate"></param>
35+ /// <param name="op"></param>
36+ /// <param name="criterion"></param>
37+ /// <exception cref="ArgumentException"></exception>
38+ public QueryFilter ( Expression < Func < TModel , object > > predicate , Operator op , TCriterion ? criterion )
39+ {
40+ var visitor = new SelectExpressionVisitor ( ) ;
41+ visitor . Visit ( predicate ) ;
42+
43+ if ( visitor . Columns . Count == 0 )
44+ throw new ArgumentException ( "Expected predicate to return a reference to a Model column." ) ;
45+
46+ if ( visitor . Columns . Count > 1 )
47+ throw new ArgumentException ( "Only one column should be returned from the predicate." ) ;
48+
49+ var filter = new QueryFilter ( visitor . Columns . First ( ) , op , criterion ) ;
50+
51+ Criteria = filter . Criteria ;
52+ Op = filter . Op ;
53+ Property = filter . Property ;
54+ }
55+ }
1156
1257 /// <inheritdoc />
1358 public class QueryFilter : IPostgrestQueryFilter
@@ -26,7 +71,6 @@ public class QueryFilter : IPostgrestQueryFilter
2671 /// <inheritdoc />
2772 public object ? Criteria { get ; private set ; }
2873
29-
3074 /// <summary>
3175 /// Contractor to use single value filtering.
3276 /// </summary>
@@ -53,54 +97,26 @@ public QueryFilter(string property, Operator op, object? criteria)
5397 Op = op ;
5498 Criteria = criteria ;
5599 break ;
56- default :
57- throw new PostgrestException ( "Advanced filters require a constructor with more specific arguments" ) { Reason = FailureHint . Reason . InvalidArgument } ;
58- }
59- }
60-
61- /// <summary>
62- /// Constructor to use multiple values as for filtering.
63- /// </summary>
64- /// <param name="property">Column name</param>
65- /// <param name="op">Operation: In, Contains, ContainedIn, or Overlap</param>
66- /// <param name="criteria"></param>
67- public QueryFilter ( string property , Operator op , IList criteria )
68- {
69- switch ( op )
70- {
71100 case Operator . In :
72101 case Operator . Contains :
73102 case Operator . ContainedIn :
74103 case Operator . Overlap :
104+ if ( criteria is IList or IDictionary )
105+ {
75106 Property = property ;
76107 Op = op ;
77108 Criteria = criteria ;
78- break ;
79- default :
80- throw new PostgrestException ( "List constructor must be used with filter that accepts an array of arguments." ) { Reason = FailureHint . Reason . InvalidArgument } ;
81- }
82109 }
83-
84- /// <summary>
85- /// Constructor to use multiple values as for filtering (using a dictionary).
86- /// </summary>
87- /// <param name="property">Column name</param>
88- /// <param name="op">Operation: In, Contains, ContainedIn, or Overlap</param>
89- /// <param name="criteria"></param>
90- public QueryFilter ( string property , Operator op , IDictionary criteria )
110+ else
91111 {
92- switch ( op )
93- {
94- case Operator . In :
95- case Operator . Contains :
96- case Operator . ContainedIn :
97- case Operator . Overlap :
98- Property = property ;
99- Op = op ;
100- Criteria = criteria ;
112+ throw new PostgrestException (
113+ "List or Dictionary must be used supplied as criteria with filters that accept an array of arguments." )
114+ { Reason = FailureHint . Reason . InvalidArgument } ;
115+ }
101116 break ;
102117 default :
103- throw new PostgrestException ( "List constructor must be used with filter that accepts an array of arguments." ) { Reason = FailureHint . Reason . InvalidArgument } ;
118+ throw new PostgrestException ( "Advanced filters require a constructor with more specific arguments" )
119+ { Reason = FailureHint . Reason . InvalidArgument } ;
104120 }
105121 }
106122
@@ -123,7 +139,8 @@ public QueryFilter(string property, Operator op, FullTextSearchConfig fullTextSe
123139 Criteria = fullTextSearchConfig ;
124140 break ;
125141 default :
126- throw new PostgrestException ( "Constructor must be called with a full text search operator" ) { Reason = FailureHint . Reason . InvalidArgument } ;
142+ throw new PostgrestException ( "Constructor must be called with a full text search operator" )
143+ { Reason = FailureHint . Reason . InvalidArgument } ;
127144 }
128145 }
129146
@@ -162,7 +179,7 @@ public QueryFilter(string property, Operator op, IntRange range)
162179 /// </summary>
163180 /// <param name="op">Operation: And, Or</param>
164181 /// <param name="filters"></param>
165- public QueryFilter ( Operator op , List < QueryFilter > filters )
182+ public QueryFilter ( Operator op , List < IPostgrestQueryFilter > filters )
166183 {
167184 switch ( op )
168185 {
@@ -172,7 +189,8 @@ public QueryFilter(Operator op, List<QueryFilter> filters)
172189 Criteria = filters ;
173190 break ;
174191 default :
175- throw new PostgrestException ( "Constructor can only be used with `or` or `and` filters" ) { Reason = FailureHint . Reason . InvalidArgument } ;
192+ throw new PostgrestException ( "Constructor can only be used with `or` or `and` filters" )
193+ { Reason = FailureHint . Reason . InvalidArgument } ;
176194 }
177195 }
178196
@@ -181,7 +199,7 @@ public QueryFilter(Operator op, List<QueryFilter> filters)
181199 /// </summary>
182200 /// <param name="op">Operation: Not.</param>
183201 /// <param name="filter"></param>
184- public QueryFilter ( Operator op , QueryFilter filter )
202+ public QueryFilter ( Operator op , IPostgrestQueryFilter filter )
185203 {
186204 switch ( op )
187205 {
@@ -190,7 +208,8 @@ public QueryFilter(Operator op, QueryFilter filter)
190208 Criteria = filter ;
191209 break ;
192210 default :
193- throw new PostgrestException ( "Constructor can only be used with `not` filter" ) { Reason = FailureHint . Reason . InvalidArgument } ;
211+ throw new PostgrestException ( "Constructor can only be used with `not` filter" )
212+ { Reason = FailureHint . Reason . InvalidArgument } ;
194213 }
195214 }
196215 }
0 commit comments