11using JsonApiDotNetCore . Internal ;
2+ using JsonApiDotNetCore . Internal . Query ;
23using System ;
34using System . Collections . Generic ;
45using System . Linq ;
@@ -13,7 +14,10 @@ public interface IResourceDefinition
1314 }
1415
1516 /// <summary>
16- /// A scoped service used to...
17+ /// exposes developer friendly hooks into how their resources are exposed.
18+ /// It is intended to improve the experience and reduce boilerplate for commonly required features.
19+ /// The goal of this class is to reduce the frequency with which developers have to override the
20+ /// service and repository layers.
1721 /// </summary>
1822 /// <typeparam name="T">The resource type</typeparam>
1923 public class ResourceDefinition < T > : IResourceDefinition where T : class , IIdentifiable
@@ -47,8 +51,10 @@ private bool InstanceOutputAttrsAreSpecified()
4751 return declaringType == derivedType ;
4852 }
4953
54+ public delegate dynamic FilterExpression ( T type ) ;
55+
5056 // TODO: need to investigate options for caching these
51- protected List < AttrAttribute > Remove ( Expression < Func < T , dynamic > > filter , List < AttrAttribute > from = null )
57+ protected List < AttrAttribute > Remove ( Expression < FilterExpression > filter , List < AttrAttribute > from = null )
5258 {
5359 from = from ?? _contextEntity . Attributes ;
5460
@@ -115,5 +121,71 @@ private List<AttrAttribute> GetOutputAttrs()
115121
116122 return _requestCachedAttrs ;
117123 }
124+
125+ /// <summary>
126+ /// Define a set of custom query expressions that can be applied
127+ /// instead of the default query behavior. A common use-case for this
128+ /// is including related resources and filtering on them.
129+ /// </summary>
130+ /// <returns>
131+ /// A set of custom queries that will be applied instead of the default
132+ /// queries for the given key. Null will be returned if default behavior
133+ /// is desired.
134+ /// </returns>
135+ /// <example>
136+ /// <code>
137+ /// protected override QueryFilters GetQueryFilters() => {
138+ /// { "facility", (t, value) => t.Include(t => t.Tenant)
139+ /// .Where(t => t.Facility == value) }
140+ /// }
141+ /// </code>
142+ ///
143+ /// If the logic is simply too complex for an in-line expression, you can
144+ /// delegate to a private method:
145+ /// <code>
146+ /// protected override QueryFilters GetQueryFilters()
147+ /// => new QueryFilters {
148+ /// { "is-active", FilterIsActive }
149+ /// };
150+ ///
151+ /// private IQueryable<Model> FilterIsActive(IQueryable<Model> query, string value)
152+ /// {
153+ /// // some complex logic goes here...
154+ /// return query.Where(x => x.IsActive == computedValue);
155+ /// }
156+ /// </code>
157+ /// </example>
158+ protected virtual QueryFilters GetQueryFilters ( ) => null ;
159+
160+ /// <summary>
161+ /// This is an alias type intended to simplify the implementation's
162+ /// method signature.
163+ /// See <see cref="GetQueryFilters" /> for usage details.
164+ /// <summary>
165+ public class QueryFilters : Dictionary < string , Func < IQueryable < T > , string , IQueryable < T > > > { }
166+
167+ /// <summary>
168+ /// Define a the default sort order if no sort key is provided.
169+ /// </summary>
170+ /// <returns>
171+ /// A list of properties and the direction they should be sorted.
172+ /// </returns>
173+ /// <example>
174+ /// <code>
175+ /// protected override PropertySortOrder GetDefaultSortOrder()
176+ /// => new PropertySortOrder {
177+ /// (t => t.Prop1, SortDirection.Ascending),
178+ /// (t => t.Prop2, SortDirection.Descending),
179+ /// };
180+ /// </code>
181+ /// </example>
182+ protected virtual PropertySortOrder GetDefaultSortOrder ( ) => null ;
183+
184+ /// <summary>
185+ /// This is an alias type intended to simplify the implementation's
186+ /// method signature.
187+ /// See <see cref="GetQueryFilters" /> for usage details.
188+ /// <summary>
189+ public class PropertySortOrder : List < ( Expression < Func < T , dynamic > > , SortDirection ) > { }
118190 }
119191}
0 commit comments