Skip to content

Commit

Permalink
[ODS-6557] Produce resource links when "SerializedData" feature enabl…
Browse files Browse the repository at this point in the history
…ed (#1188)
  • Loading branch information
gmcelhanon authored Nov 27, 2024
1 parent aa35e6e commit 59c9de1
Show file tree
Hide file tree
Showing 70 changed files with 138,153 additions and 36,088 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
using System.Threading;
using System.Threading.Tasks;
using EdFi.Ods.Common;
using EdFi.Ods.Common.Configuration;
using EdFi.Ods.Common.Constants;
using EdFi.Ods.Common.Context;
using EdFi.Ods.Common.Infrastructure.Pipelines;
using EdFi.Ods.Common.Repositories;
using EdFi.Ods.Common.Security.Claims;
using Microsoft.AspNetCore.Http;

namespace EdFi.Ods.Api.Infrastructure.Pipelines.Steps
{
Expand All @@ -17,29 +23,25 @@ public class MapResourceModelToEntityModel<TContext, TResult, TResourceModel, TE
where TResourceModel : class, IMappable, IHasETag
where TEntityModel : class, new()
{
public void Execute(TContext context, TResult result)
public Task ExecuteAsync(TContext context, TResult result, CancellationToken cancellationToken)
{
// NOTE this step will always run synchronously so we are not moving the logic to the async method.
try
{
if (context.Resource == default(TResourceModel))
{
return;
return Task.CompletedTask;
}

var model = new TEntityModel();
context.Resource.Map(model);
context.PersistentModel = model;
var entity = new TEntityModel();
context.Resource.Map(entity);
context.PersistentModel = entity;
}
catch (Exception ex)
{
result.Exception = ex;
}
}

public Task ExecuteAsync(TContext context, TResult result, CancellationToken cancellationToken)
{
Execute(context, result);
return Task.CompletedTask;
}
}
Expand Down
21 changes: 19 additions & 2 deletions Application/EdFi.Ods.Common/Configuration/ApiSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// 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;
Expand Down Expand Up @@ -41,7 +42,17 @@ public ApiSettings()

public int[] Years { get; set; }

public List<Feature> Features { get; set; } = new();
private List<Feature> _features = new();

public List<Feature> Features
{
get => _features;
set
{
_features = value;
_featureEnabledByName = new();
}
}

public List<ScheduledJobSettings> ScheduledJobs { get; set; } = new();

Expand Down Expand Up @@ -120,7 +131,13 @@ public string[] GetOdsContextRouteTemplateKeys()
return Array.Empty<string>();
}

private ConcurrentDictionary<string, bool> _featureEnabledByName = new(StringComparer.OrdinalIgnoreCase);

public bool IsFeatureEnabled(string featureName)
=> Features.SingleOrDefault(x => x.Name.EqualsIgnoreCase(featureName) && x.IsEnabled) != null;
{
return _featureEnabledByName.GetOrAdd(featureName,
static (n, features)
=> features.SingleOrDefault(x => x.Name.EqualsIgnoreCase(n) && x.IsEnabled) != null, Features);
}
}
}
1 change: 1 addition & 0 deletions Application/EdFi.Ods.Common/Constants/ApiFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class ApiFeature : Enumeration<ApiFeature, string>
public static readonly ApiFeature MultiTenancy = new ApiFeature("multiTenancy", "Multi-Tenancy");
public static readonly ApiFeature Notifications = new ApiFeature("notifications", "Notifications");
public static readonly ApiFeature SerializedData = new ApiFeature("serializedData", "SerializedData");
public static readonly ApiFeature ResourceLinks = new ApiFeature("resourceLinks", "ResourceLinks");

public ApiFeature(string value, string displayName)
: base(value, displayName) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,7 @@ public virtual string GetGreatestString(string expression1, string expression2)
{
return $"GREATEST({expression1}, {expression2})";
}

public abstract int GetMaxParameterCount();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,11 @@ public override (string sql, object parameters) GetInClause(string columnName, s

return ($"{columnName} IN (VALUES ({string.Join("), (", parameters.Keys)}) )", parameters);
}

/// <summary>
/// Gets the maximum number of allowed parameters for PostgreSQL (see https://www.postgresql.org/docs/current/limits.html).
/// </summary>
/// <returns>65535</returns>
public override int GetMaxParameterCount() => 65535;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,11 @@ public override string GetGreatestString(string expression1, string expression2)
// For SQL 2022 and later, this override is not need. For SQL 2019 and earlier, CASE must be used
return $"CASE WHEN {expression1} > {expression2} THEN {expression1} ELSE {expression2} END";
}

/// <summary>
/// Gets the maximum number of allowed parameters for SQL Server (see https://learn.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server?view=sql-server-ver16).
/// </summary>
/// <returns>2100</returns>
public override int GetMaxParameterCount() => 2100;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using EdFi.Ods.Common.Infrastructure.Extensibility;
using EdFi.Ods.Common.Models;
using EdFi.Ods.Common.Profiles;
using EdFi.Ods.Common.Repositories;
using EdFi.Ods.Common.Security.Claims;
using NHibernate.Engine;

Expand All @@ -30,13 +31,17 @@ public static class GeneratedArtifactStaticDependencies
private static Lazy<IContextProvider<ProfileContentTypeContext>> _profileContentTypeContextProvider;
private static Lazy<IContextProvider<UniqueIdLookupsByUsiContext>> _uniqueIdLookupsContextProvider;
private static Lazy<IContextProvider<UsiLookupsByUniqueIdContext>> _usiLookupsContextProvider;
private static Lazy<IContextProvider<ReferenceDataLookupContext>> _referenceDataLookupContextProvider;
private static Lazy<IContextProvider<DataPolicyException>> _dataPolicyExceptionContextProvider;
private static Lazy<StringComparer> _databaseEngineSpecificStringComparer;
private static Lazy<IDescriptorResolver> _descriptorResolver;
private static Lazy<IEntityExtensionRegistrar> _entityExtensionRegistrar;
private static Lazy<IEntityExtensionsFactory> _entityExtensionsFactory;
private static Lazy<ISessionFactoryImplementor> _sessionFactory;

private static bool _serializedDataEnabled;
private static bool _resourceLinksEnabled;

public static IAuthorizationContextProvider AuthorizationContextProvider => _authorizationContextProvider?.Value;
public static IResourceModelProvider ResourceModelProvider => _resourceModelProvider?.Value;
public static IProfileResourceModelProvider ProfileResourceModelProvider => _profileResourceModelProvider?.Value;
Expand All @@ -46,12 +51,15 @@ public static class GeneratedArtifactStaticDependencies
public static IContextProvider<ProfileContentTypeContext> ProfileContentTypeContextProvider => _profileContentTypeContextProvider?.Value;
public static IContextProvider<UniqueIdLookupsByUsiContext> UniqueIdLookupsByUsiContextProvider => _uniqueIdLookupsContextProvider?.Value;
public static IContextProvider<UsiLookupsByUniqueIdContext> UsiLookupsByUniqueIdContextProvider => _usiLookupsContextProvider?.Value;
public static IContextProvider<ReferenceDataLookupContext> ReferenceDataLookupContextProvider => _referenceDataLookupContextProvider?.Value;
public static IContextProvider<DataPolicyException> DataPolicyExceptionContextProvider => _dataPolicyExceptionContextProvider?.Value;
public static StringComparer DatabaseEngineSpecificStringComparer => _databaseEngineSpecificStringComparer?.Value;
public static IDescriptorResolver DescriptorResolver => _descriptorResolver?.Value;
public static IEntityExtensionRegistrar EntityExtensionRegistrar => _entityExtensionRegistrar?.Value;
public static IEntityExtensionsFactory EntityExtensionsFactory => _entityExtensionsFactory?.Value;
public static ISessionFactoryImplementor SessionFactory => _sessionFactory?.Value;
public static bool SerializedDataEnabled => _serializedDataEnabled;
public static bool ResourceLinksEnabled => _resourceLinksEnabled;

/// <summary>
/// Provides a mechanism for providing resolution of container managed components (intended for use only
Expand Down Expand Up @@ -104,6 +112,11 @@ public static void Set(Func<IContextProvider<UsiLookupsByUniqueIdContext>> resol
_usiLookupsContextProvider = new Lazy<IContextProvider<UsiLookupsByUniqueIdContext>>(resolver);
}

public static void Set(Func<IContextProvider<ReferenceDataLookupContext>> resolver)
{
_referenceDataLookupContextProvider = new Lazy<IContextProvider<ReferenceDataLookupContext>>(resolver);
}

public static void Set(Func<IContextProvider<DataPolicyException>> resolver)
{
_dataPolicyExceptionContextProvider = new Lazy<IContextProvider<DataPolicyException>>(resolver);
Expand Down Expand Up @@ -133,6 +146,12 @@ public static void Set(Func<ISessionFactoryImplementor> resolver)
{
_sessionFactory = new Lazy<ISessionFactoryImplementor>(resolver);
}

public static void SetEnabledFeatures(bool? serializedDataEnabled = null, bool? resourceLinksEnabled = null)
{
_serializedDataEnabled = serializedDataEnabled ?? _serializedDataEnabled;
_resourceLinksEnabled = resourceLinksEnabled ?? _resourceLinksEnabled;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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.

namespace EdFi.Ods.Common.Extensions;

public static class EntityReferenceDataExtensions
{
/// <summary>
/// Indicates whether the supplied object instance's type name matches the pattern used by NHibernate when building
/// proxied objects for lazy loading purposes.
/// </summary>
/// <param name="instance">The entity instance to be evaluated.</param>
/// <returns><b>true</b> if the instance appears to be proxied; otherwise <b>false</b>.</returns>
public static bool IsProxied(this IEntityReferenceData instance)
{
if (instance == null)
{
return false;
}

return instance.GetType().Name.EndsWith("Proxy");
}
}
37 changes: 37 additions & 0 deletions Application/EdFi.Ods.Common/IEntityReferenceData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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 EdFi.Ods.Common.Models.Domain;

namespace EdFi.Ods.Common;

/// <summary>
/// Defines members for obtaining key values and reference data (including Id and Discriminator).
/// </summary>
public interface IEntityReferenceData : IHasPrimaryKeyValues
{
/// <summary>
/// Gets the schema/entity name of the associated <see cref="Entity" />.
/// </summary>
FullName FullName { get; }

/// <summary>
/// The id of the referenced entity (used as the resource identifier in the API).
/// </summary>
Guid? Id { get; set; }

/// <summary>
/// Gets and sets the discriminator value which identifies the concrete sub-type of the referenced entity
/// when that entity has been derived; otherwise <b>null</b>.
/// </summary>
string Discriminator { get; set; }

/// <summary>
/// Indicates whether the reference is fully defined.
/// </summary>
/// <returns><b>true</b> if the reference's data is fully defined; otherwise <b>false</b>.</returns>
bool IsFullyDefined();
}
Loading

0 comments on commit 59c9de1

Please sign in to comment.