66using SimpleIdServer . Persistence . Filters ;
77using SimpleIdServer . Scim . Domain ;
88using SimpleIdServer . Scim . Domains ;
9+ using SimpleIdServer . Scim . Parser . Expressions ;
910using SimpleIdServer . Scim . Persistence . MongoDB . Extensions ;
10- using System ;
11+ using SimpleIdServer . Scim . Persistence . MongoDB . Models ;
1112using System . Collections . Generic ;
1213using System . Linq ;
1314using System . Threading ;
@@ -63,7 +64,7 @@ public async Task<SearchSCIMRepresentationsResponse> FindSCIMRepresentations(Sea
6364 int total = 0 ;
6465 if ( parameter . Filter != null )
6566 {
66- IQueryable < EnrichedAttribute > filteredRepresentationAttributes = from a in _scimDbContext . SCIMRepresentationAttributeLst . AsQueryable ( ) . Where ( a => parameter . SchemaNames . Contains ( a . Namespace ) )
67+ var filteredRepresentationAttributes = from a in _scimDbContext . SCIMRepresentationAttributeLst . AsQueryable ( ) . Where ( a => parameter . SchemaNames . Contains ( a . Namespace ) || a . ResourceType == parameter . ResourceType )
6768 join b in _scimDbContext . SCIMRepresentationAttributeLst . AsQueryable ( ) on a . ParentAttributeId equals b . Id into Parents
6869 select new EnrichedAttribute
6970 {
@@ -86,32 +87,175 @@ join b in _scimDbContext.SCIMRepresentationAttributeLst.AsQueryable() on a.Paren
8687 . CountAsync ( ) ;
8788 }
8889
89-
90- var filteredRepresentations = _scimDbContext . SCIMRepresentationLst . AsQueryable ( ) . Where ( s => s . ResourceType == parameter . ResourceType ) ;
90+
91+ var filteredRepresentations = _scimDbContext . SCIMRepresentationLst . AsQueryable ( )
92+ . Where ( r => r . ResourceType == parameter . ResourceType ) ;
9193 if ( filteredRepresentationIds != null )
94+ {
9295 filteredRepresentations = filteredRepresentations . Where ( r => filteredRepresentationIds . Contains ( r . Id ) ) ;
96+ }
9397
94- if ( parameter . SortBy == null )
95- filteredRepresentations = filteredRepresentations . OrderBy ( s => s . Id ) ;
96- else
98+ var paginationResult = await OrderByAndPaginate ( filteredRepresentations , parameter ) ;
99+ filteredRepresentations = paginationResult . Query ;
100+ var filteredRepresentationsWithAttributes = from a in filteredRepresentations
101+ join b in _scimDbContext . SCIMRepresentationAttributeLst . AsQueryable ( ) on a . Id equals b . RepresentationId into Attributes
102+ select new
103+ {
104+ Representation = a ,
105+ Attributes = Attributes
106+ } ;
107+ var representationWithAttributes = await filteredRepresentationsWithAttributes
108+ . ToListAsync ( ) ;
109+ if ( paginationResult . OrderedRepresentationIds != null )
97110 {
98- filteredRepresentations = parameter . SortBy . EvaluateMongoDbOrderBy (
99- filteredRepresentations ,
100- parameter . SortOrder ?? SearchSCIMRepresentationOrders . Descending ) ;
111+ representationWithAttributes = representationWithAttributes . Select ( r => new
112+ {
113+ Representation = r ,
114+ Order = paginationResult . OrderedRepresentationIds . IndexOf ( r . Representation . Id )
115+ } )
116+ . OrderBy ( r => r . Order )
117+ . Select ( r => r . Representation )
118+ . ToList ( ) ;
119+ }
120+
121+ var representations = new List < SCIMRepresentation > ( ) ;
122+ foreach ( var record in representationWithAttributes )
123+ {
124+ var representation = record . Representation ;
125+ representation . FlatAttributes = record . Attributes . ToList ( ) ;
126+ representations . Add ( representation ) ;
101127 }
102128
103- var representations = await filteredRepresentations
104- . Skip ( parameter . StartIndex <= 1 ? 0 : parameter . StartIndex - 1 )
105- . Take ( parameter . Count )
106- . ToListAsync ( ) ;
107- var representationIds = representations . Select ( r => r . Id ) ;
108- var representationAttributes = await _scimDbContext . SCIMRepresentationAttributeLst . AsQueryable ( )
109- . Where ( a => representationIds . Contains ( a . RepresentationId ) )
110- . ToListAsync ( ) ;
111- foreach ( var representation in representations )
112- representation . FlatAttributes = representationAttributes . Where ( a => a . RepresentationId == representation . Id ) . ToList ( ) ;
113129 representations . FilterAttributes ( parameter . IncludedAttributes , parameter . ExcludedAttributes ) ;
114130 return new SearchSCIMRepresentationsResponse ( total , representations ) ;
115131 }
132+
133+ private async Task < PaginationResult > OrderByAndPaginate (
134+ IMongoQueryable < SCIMRepresentationModel > representations ,
135+ SearchSCIMRepresentationsParameter parameter )
136+ {
137+ if ( parameter . SortBy == null ) return new PaginationResult
138+ {
139+ Query = representations
140+ . OrderBy ( r => r . Id )
141+ . Skip ( parameter . StartIndex <= 1 ? 0 : parameter . StartIndex - 1 )
142+ . Take ( parameter . Count )
143+ } ;
144+ var sortBy = parameter . SortBy as SCIMAttributeExpression ;
145+ var order = parameter . SortOrder ?? SearchSCIMRepresentationOrders . Ascending ;
146+ var result = OrderByMetadataAndPaginate ( sortBy ,
147+ representations ,
148+ order ,
149+ parameter . StartIndex ,
150+ parameter . Count ) ;
151+ if ( result != null ) return result ;
152+ return await OrderByPropertyAndPaginate (
153+ representations ,
154+ sortBy ,
155+ parameter . SchemaNames ,
156+ order ,
157+ parameter . StartIndex ,
158+ parameter . Count ) ;
159+ }
160+
161+ private PaginationResult OrderByMetadataAndPaginate (
162+ SCIMAttributeExpression attrExpression ,
163+ IMongoQueryable < SCIMRepresentationModel > representations ,
164+ SearchSCIMRepresentationOrders order ,
165+ int startIndex ,
166+ int count )
167+ {
168+ var fullPath = attrExpression . GetFullPath ( ) ;
169+ IMongoQueryable < SCIMRepresentationModel > result = null ;
170+ switch ( fullPath )
171+ {
172+ case StandardSCIMRepresentationAttributes . Id :
173+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . Id ) : representations . OrderByDescending ( r => r . Id ) ;
174+ break ;
175+ case StandardSCIMRepresentationAttributes . ExternalId :
176+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . ExternalId ) : representations . OrderByDescending ( r => r . ExternalId ) ;
177+ break ;
178+ case $ "{ StandardSCIMRepresentationAttributes . Meta } .{ StandardSCIMMetaAttributes . ResourceType } ":
179+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . ResourceType ) : representations . OrderByDescending ( r => r . ResourceType ) ;
180+ break ;
181+ case $ "{ StandardSCIMRepresentationAttributes . Meta } .{ StandardSCIMMetaAttributes . Created } ":
182+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . Created ) : representations . OrderByDescending ( r => r . Created ) ;
183+ break ;
184+ case $ "{ StandardSCIMRepresentationAttributes . Meta } .{ StandardSCIMMetaAttributes . LastModified } ":
185+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . LastModified ) : representations . OrderByDescending ( r => r . LastModified ) ;
186+ break ;
187+ case $ "{ StandardSCIMRepresentationAttributes . Meta } .{ StandardSCIMMetaAttributes . Version } ":
188+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . Version ) : representations . OrderByDescending ( r => r . Version ) ;
189+ break ;
190+ case StandardSCIMRepresentationAttributes . DisplayName :
191+ result = order == SearchSCIMRepresentationOrders . Ascending ? representations . OrderBy ( r => r . DisplayName ) : representations . OrderByDescending ( r => r . DisplayName ) ;
192+ break ;
193+ default :
194+ return null ;
195+ }
196+
197+ return new PaginationResult
198+ {
199+ Query = result . Skip ( startIndex <= 1 ? 0 : startIndex - 1 ) . Take ( count )
200+ } ;
201+ }
202+
203+ private async Task < PaginationResult > OrderByPropertyAndPaginate (
204+ IMongoQueryable < SCIMRepresentationModel > representations ,
205+ SCIMAttributeExpression attrExpression ,
206+ List < string > schemaNames ,
207+ SearchSCIMRepresentationOrders order ,
208+ int startIndex ,
209+ int count )
210+ {
211+ var fullPath = attrExpression . GetFullPath ( ) ;
212+ var attributes = _scimDbContext . SCIMRepresentationAttributeLst
213+ . AsQueryable ( )
214+ . Where ( r => r . FullPath == fullPath && schemaNames . Contains ( r . Namespace ) ) ;
215+ var lastExpr = attrExpression . GetLastChild ( ) ;
216+ switch ( lastExpr . SchemaAttribute . Type )
217+ {
218+ case SCIMSchemaAttributeTypes . STRING :
219+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueString ) : attributes . OrderByDescending ( a => a . ValueString ) ;
220+ break ;
221+ case SCIMSchemaAttributeTypes . BOOLEAN :
222+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueBoolean ) : attributes . OrderByDescending ( a => a . ValueBoolean ) ;
223+ break ;
224+ case SCIMSchemaAttributeTypes . DECIMAL :
225+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueDecimal ) : attributes . OrderByDescending ( a => a . ValueDecimal ) ;
226+ break ;
227+ case SCIMSchemaAttributeTypes . INTEGER :
228+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueInteger ) : attributes . OrderByDescending ( a => a . ValueInteger ) ;
229+ break ;
230+ case SCIMSchemaAttributeTypes . DATETIME :
231+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueDateTime ) : attributes . OrderByDescending ( a => a . ValueDateTime ) ;
232+ break ;
233+ case SCIMSchemaAttributeTypes . BINARY :
234+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueBinary ) : attributes . OrderByDescending ( a => a . ValueBinary ) ;
235+ break ;
236+ case SCIMSchemaAttributeTypes . REFERENCE :
237+ attributes = order == SearchSCIMRepresentationOrders . Ascending ? attributes . OrderBy ( a => a . ValueReference ) : attributes . OrderByDescending ( a => a . ValueReference ) ;
238+ break ;
239+ }
240+
241+ var representationIds = ( await attributes
242+ . Select ( a => a . RepresentationId )
243+ . Skip ( startIndex <= 1 ? 0 : startIndex - 1 )
244+ . Take ( count )
245+ . ToListAsync ( ) )
246+ . Distinct ( )
247+ . ToList ( ) ;
248+ return new PaginationResult
249+ {
250+ Query = representations . Where ( r => representationIds . Contains ( r . Id ) ) ,
251+ OrderedRepresentationIds = representationIds
252+ } ;
253+ }
254+
255+ private record PaginationResult
256+ {
257+ public IMongoQueryable < SCIMRepresentationModel > Query { get ; set ; }
258+ public List < string > OrderedRepresentationIds { get ; set ; }
259+ }
116260 }
117261}
0 commit comments