-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ODS-5665] Add ability to query organizations by an identification co…
…de (#1166)
- Loading branch information
Showing
23 changed files
with
1,665 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
...mmon/Providers/Queries/Criteria/IdentificationCodeAggregateRootQueryCriteriaApplicator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Licensed to the Ed-Fi Alliance under one or more agreements. | ||
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0. | ||
// See the LICENSE and NOTICES files in the project root for more information. | ||
|
||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using EdFi.Common.Configuration; | ||
using EdFi.Common.Extensions; | ||
using EdFi.Ods.Common.Database.Querying; | ||
using EdFi.Ods.Common.Descriptors; | ||
using EdFi.Ods.Common.Models; | ||
using EdFi.Ods.Common.Models.Domain; | ||
using EdFi.Ods.Common.Models.Resource; | ||
using EdFi.Ods.Common.Providers.Criteria; | ||
|
||
namespace EdFi.Ods.Common.Providers.Queries.Criteria; | ||
|
||
/// <summary> | ||
/// Applies criteria to a query based on identification codes property values | ||
/// </summary> | ||
public class IdentificationCodeAggregateRootQueryCriteriaApplicator : IAggregateRootQueryCriteriaApplicator | ||
{ | ||
private readonly IDescriptorResolver _descriptorResolver; | ||
private readonly IResourceModelProvider _resourceModelProvider; | ||
private readonly IResourceIdentificationCodePropertiesProvider _resourceIdentificationCodePropertiesProvider; | ||
private readonly DatabaseEngine _databaseEngine; | ||
|
||
private const string IdentificationCodeTableAlias = "idct"; | ||
private readonly ConcurrentDictionary<FullName, Join> _identificationCodeTableJoinByRootEntityName = new(); | ||
|
||
public IdentificationCodeAggregateRootQueryCriteriaApplicator( | ||
IDescriptorResolver descriptorResolver, | ||
IResourceModelProvider resourceModelProvider, | ||
IResourceIdentificationCodePropertiesProvider resourceIdentificationCodePropertiesProvider, | ||
DatabaseEngine databaseEngine) | ||
{ | ||
_descriptorResolver = descriptorResolver; | ||
_resourceIdentificationCodePropertiesProvider = resourceIdentificationCodePropertiesProvider; | ||
_resourceModelProvider = resourceModelProvider; | ||
_databaseEngine = databaseEngine; | ||
} | ||
|
||
public void ApplyAdditionalParameters(QueryBuilder queryBuilder, Entity entity, AggregateRootWithCompositeKey specification, | ||
IDictionary<string, string> additionalParameters) | ||
{ | ||
if (additionalParameters == null | ||
|| !additionalParameters.Any() | ||
|| additionalParameters.All( | ||
ap => AggregateRootCriteriaProviderHelpers.PropertiesToIgnore.Contains(ap.Key, StringComparer.OrdinalIgnoreCase))) | ||
{ | ||
return; | ||
} | ||
|
||
var resource = _resourceModelProvider.GetResourceModel().GetResourceByFullName(entity.FullName); | ||
|
||
// If the entity does not have an identificationCodes collection with queryable properties, return | ||
if (!_resourceIdentificationCodePropertiesProvider.TryGetIdentificationCodeProperties( | ||
resource, out List<ResourceProperty> identificationCodeProperties)) | ||
{ | ||
return; | ||
} | ||
|
||
// Find any supplied additionalParameters with a non-default value and name matching that of a queryable identificationCode property, if none then return | ||
var applicableAdditionalParameters = additionalParameters | ||
.Where( | ||
x => !x.Value.IsDefaultValue() | ||
&& identificationCodeProperties.Any(y => y.PropertyName.Equals(x.Key, StringComparison.OrdinalIgnoreCase))) | ||
.ToArray(); | ||
|
||
if (applicableAdditionalParameters.Length == 0) | ||
{ | ||
return; | ||
} | ||
|
||
var identificationCodeTableJoin = | ||
GetIdentificationCodeEntityTableJoin(entity, identificationCodeProperties.First().EntityProperty.Entity); | ||
|
||
queryBuilder.Join(identificationCodeTableJoin.TableName, _ => identificationCodeTableJoin); | ||
|
||
ApplyParameterValuesToQueryBuilder( | ||
queryBuilder, applicableAdditionalParameters, identificationCodeProperties); | ||
} | ||
|
||
private void ApplyParameterValuesToQueryBuilder(QueryBuilder queryBuilder, | ||
IEnumerable<KeyValuePair<string, string>> parameterValuesByName, | ||
List<ResourceProperty> identificationCodeProperties) | ||
{ | ||
foreach (KeyValuePair<string, string> parameterKeyValuePair in parameterValuesByName) | ||
{ | ||
var identificationCodeProperty = | ||
identificationCodeProperties.FirstOrDefault( | ||
p => p.PropertyName.Equals(parameterKeyValuePair.Key, StringComparison.OrdinalIgnoreCase)); | ||
|
||
if (identificationCodeProperty == null) | ||
{ | ||
continue; | ||
} | ||
|
||
var queryParameterValue = GetQueryParameterValueForProperty(identificationCodeProperty, parameterKeyValuePair.Value); | ||
|
||
if (identificationCodeProperty.IsDescriptorUsage && queryParameterValue == null) | ||
{ | ||
// Descriptor did not match any value -- criteria should exclude all entries | ||
// Since no additional criteria need to be applied, exit the loop | ||
queryBuilder.WhereRaw("1 = 0"); | ||
break; | ||
} | ||
|
||
queryBuilder.Where( | ||
$"{IdentificationCodeTableAlias}.{identificationCodeProperty.EntityProperty}", queryParameterValue); | ||
} | ||
|
||
return; | ||
|
||
object GetQueryParameterValueForProperty(ResourceProperty property, string parameterValue) | ||
{ | ||
if (!property.IsDescriptorUsage) | ||
{ | ||
return parameterValue; | ||
} | ||
|
||
var lookupId = _descriptorResolver.GetDescriptorId(property.DescriptorName, parameterValue); | ||
|
||
return lookupId == 0 | ||
? null | ||
: lookupId; | ||
} | ||
} | ||
|
||
private Join GetIdentificationCodeEntityTableJoin(Entity rootEntity, Entity identificationCodeEntity) | ||
{ | ||
return _identificationCodeTableJoinByRootEntityName.GetOrAdd( | ||
rootEntity.FullName, _ => | ||
{ | ||
string alias = rootEntity.RootTableAlias(); | ||
|
||
var join = new Join( | ||
$"{identificationCodeEntity.Schema}.{identificationCodeEntity.TableName(_databaseEngine)}" | ||
.Alias(IdentificationCodeTableAlias)); | ||
|
||
foreach (var entityIdentificationCodePropertyColumnName in GetIdentificationCodeEntityTableJoinColumnNames( | ||
identificationCodeEntity)) | ||
{ | ||
join.On( | ||
$"{alias}.{entityIdentificationCodePropertyColumnName}", | ||
$"{IdentificationCodeTableAlias}.{entityIdentificationCodePropertyColumnName}"); | ||
} | ||
|
||
return join; | ||
}); | ||
|
||
IEnumerable<string> GetIdentificationCodeEntityTableJoinColumnNames(Entity identificationCodeEntity) | ||
{ | ||
return identificationCodeEntity.Identifier.Properties | ||
.Where(p => p.IsFromParent && p.IsIdentifying) | ||
.Select(p => p.ColumnName(_databaseEngine, p.PropertyName)).ToArray(); | ||
} | ||
} | ||
|
||
public static string IdentificationCodeEntityTableAlias() => IdentificationCodeTableAlias; | ||
} |
26 changes: 26 additions & 0 deletions
26
Application/EdFi.Ods.Common/Providers/Queries/EntityExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Licensed to the Ed-Fi Alliance under one or more agreements. | ||
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0. | ||
// See the LICENSE and NOTICES files in the project root for more information. | ||
|
||
using EdFi.Ods.Common.Models.Domain; | ||
|
||
namespace EdFi.Ods.Common.Providers.Queries; | ||
|
||
public static class EntityExtensions | ||
{ | ||
private const string BaseAlias = "b"; | ||
private const string StandardAlias = "r"; | ||
|
||
/// <summary> | ||
/// Determines the appropriate table alias for the given aggregate root entity. | ||
/// </summary> | ||
/// <param name="aggregateRootEntity">The aggregate root entity to determine the alias for.</param> | ||
/// <returns> | ||
/// Returns "b" if the entity is derived, otherwise returns "r". | ||
/// </returns> | ||
public static string RootTableAlias(this Entity aggregateRootEntity) | ||
{ | ||
return aggregateRootEntity.IsDerived ? BaseAlias : StandardAlias; | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
Application/EdFi.Ods.Common/Providers/Queries/IResourceIdentificationCodePropertyProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// Licensed to the Ed-Fi Alliance under one or more agreements. | ||
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0. | ||
// See the LICENSE and NOTICES files in the project root for more information. | ||
|
||
using System.Collections.Generic; | ||
using EdFi.Ods.Common.Models.Resource; | ||
|
||
namespace EdFi.Ods.Common.Providers.Queries; | ||
|
||
/// <summary> | ||
/// Provides an interface for retrieving the queryable properties of the identificationCode collection of a resource | ||
/// </summary> | ||
public interface IResourceIdentificationCodePropertiesProvider | ||
{ | ||
/// <summary> | ||
/// Attempts to get the queryable properties of a resource's identificationCode collection. | ||
/// </summary> | ||
/// <param name="resource">The entity to try and get the identificationCode properties for.</param> | ||
/// <param name="queryableIdentificationCodeProperties">The queryable properties of the identificationCode of the <paramref name="resource"/>.</param> | ||
/// <returns><c>true</c> if the resource has an identificationCode collection with any queryable properties.</returns> | ||
public bool TryGetIdentificationCodeProperties(Resource resource, | ||
out List<ResourceProperty> queryableIdentificationCodeProperties); | ||
} |
Oops, something went wrong.