public void MapAndDefaultIncludesAttribute() { _expander = new Expander(); var config = new PopcornConfiguration(_expander); Assert.ThrowsException <MultipleDefaultsException>(() => config.Map <RootObject, IncludeByDefaultRootObjectProjection>($"[{nameof(IncludeByDefaultRootObjectProjection.Id)},{nameof(IncludeByDefaultRootObjectProjection.StringValue)}]")); }
public void DefaultIncludesAttribute() { _expander = new Expander(); var config = new PopcornConfiguration(_expander); config.Map <RootObject, IncludeByDefaultRootObjectProjection>(); var root = new RootObject { Id = Guid.NewGuid(), StringValue = "Name", NonIncluded = "A description", ExcludedFromProjection = "Some Details", Child = new ChildObject { Id = Guid.NewGuid(), Name = "Name", Description = "Description" } }; var result = _expander.Expand(root); result.ShouldNotBeNull(); IncludeByDefaultRootObjectProjection projection = result as IncludeByDefaultRootObjectProjection; projection.ShouldNotBeNull(); projection.StringValue.ShouldBe(root.StringValue); projection.Id.ShouldBe(root.Id); projection.NonIncluded.ShouldBeNull(); projection.Child.ShouldBeNull(); }
public void ExpandFromProof() { var expander = new Expander(); var config = new PopcornConfiguration(expander); config.ScanAssemblyForMapping(this.GetType().GetTypeInfo().Assembly); ExpandFromClass testObject = new ExpandFromClass { Field1 = "field1", Field2 = 2 }; var result = (ExpandFromClassProjection)expander.Expand(testObject, null); Assert.AreEqual(testObject.Field1, result.Field1); Assert.AreEqual(testObject.Field2, result.Field2); }
/// <summary> /// Configure the AspNet Core MVC options to include an Api Expander. Allow the caller to configure it with an action. /// </summary> /// <param name="options"></param> /// <param name="configure"></param> public static void UsePopcorn(this HttpConfiguration options, Action <PopcornConfiguration> configure = null) { // Create an expander object var expander = new Expander(); var configuration = new PopcornConfiguration(expander); // optionally configure this expander if (configure != null) { configure(configuration); } // Assign a global expander that'll run on all endpoints options.Filters.Add(new ExpandActionFilter(expander, configuration.Context, configuration.Inspector, configuration.ApplyToAllEndpoints)); }
public void SetupExpanderRegistry() { _expander = new Expander(); var config = new PopcornConfiguration(_expander); config.Map <UserRelationship, UserRelationship>(config: builder => { builder.AlternativeMap <UserRelationshipNameProjection>(); builder.AlternativeMap <UserRelationshipEmailProjection>(); builder.AlternativeMap <UserRelationshipMixedProjection>(); }); config.Map <User, UserFullProjection>(config: builder => { builder.AlternativeMap <UserWithNameProjection>(); builder.AlternativeMap <UserWithEmailProjection>(); }); config.Map <UserCollection, UserCollectionProjection>(); }
public async Task SimpleExpandLazyLoading() { using (var context = new TestContext(dbname)) { // Get the employee that has cars lazily loaded var employee = await context.Employees.FirstOrDefaultAsync(); employee.ShouldNotBeNull(); employee.Cars.ShouldNotBeNull(); // Set up our expander var expander = new Expander(); var config = new PopcornConfiguration(expander); config.EnableBlindExpansion(true); // Expand it and make sure we only have our three expected properties. var expanded = (Dictionary <string, object>)expander.Expand(employee); expanded.ShouldNotBeNull(); expanded.Count.ShouldBe(3); } }
public void Setup() { _expander = new Expander(); var config = new PopcornConfiguration(_expander); config.MapEntityFramework <Project, ProjectProjection, TestModelContext>(TestModelContext.ConfigureOptions(), null, (definition) => { definition.Translate(o => o.Id, () => Guid.NewGuid()); }); config.MapEntityFramework <PopcornNetStandardTest.Models.Environment, EnvironmentProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <Credential, CredentialProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <CredentialDefinition, CredentialDefinitionProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <CredentialType, CredentialTypeProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <CredentialKeyValue, CredentialKeyValueProjection, TestModelContext>(TestModelContext.ConfigureOptions()); using (var db = new TestModelContext()) { db.Database.EnsureDeleted(); } using (var db = new TestModelContext()) { db.Database.EnsureCreated(); } }
public void SetupExpanderRegistry() { _expander = new Expander(); var config = new PopcornConfiguration(_expander); config.Map <RootObject, RootObjectProjection>($"[{nameof(RootObjectProjection.Id)},{nameof(RootObjectProjection.StringValue)},{nameof(RootObjectProjection.NonIncluded)}]", (definition) => { definition.Translate(o => o.ValueFromTranslator, () => 5.2); definition.Translate(o => o.ComplexFromTranslator, () => new ChildObjectProjection { Id = new Guid(), Name = "Complex trans name", Description = "Complex trans description" }); }); config.Map <ChildObject, ChildObjectProjection>(); config.Map <DerivedChildObject, DerivedChildObjectProjection>(); config.Map <Loop, LoopProjection>(); config.Map <EntityFromFactory, EntityFromFactoryProjection>(); config.AssignFactory <EntityFromFactoryProjection>(() => new EntityFromFactoryProjection { ShouldBeEmpty = "Generated" }); }
public void Setup() { _expander = new Expander(); var config = new PopcornConfiguration(_expander); config.MapEntityFramework <Project, ProjectProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <PopcornCoreTest.Models.Environment, EnvironmentProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <Credential, CredentialProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <CredentialDefinition, CredentialDefinitionProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <CredentialType, CredentialTypeProjection, TestModelContext>(TestModelContext.ConfigureOptions()); config.MapEntityFramework <CredentialKeyValue, CredentialKeyValueProjection, TestModelContext>(TestModelContext.ConfigureOptions()); using (var db = new TestModelContext()) { db.Database.EnsureDeleted(); } using (var db = new TestModelContext()) { db.Database.EnsureCreated(); } }
/// <summary> /// Helper function creating a mapping from a source type to a destination type. Will attempt to auto-load navigation properties as needed. /// </summary> /// <param name="optionsBuilder"></param> /// <param name="defaultIncludes"></param> /// <param name="self">todo: describe self parameter on MapEntityFramework</param> /// <typeparam name="TSourceType"></typeparam> /// <typeparam name="TDestType"></typeparam> /// <typeparam name="TContext"></typeparam> /// <returns></returns> public static PopcornConfiguration MapEntityFramework <TSourceType, TDestType, TContext>( this PopcornConfiguration self, DbContextOptionsBuilder <TContext> optionsBuilder, string defaultIncludes = null) where TContext : DbContext where TSourceType : class where TDestType : class { return(self.Map <TSourceType, TDestType>(defaultIncludes, (definition) => { definition // Before dealing with this object, create a context to use .BeforeExpansion((destinationObject, sourceObject, context) => { // Do some reference counting here if (!context.ContainsKey(DbKey)) { DbContext db = ConstructDbContextWithOptions(optionsBuilder); try { db.Attach(sourceObject); context[DbKey] = db; context[DbCountKey] = 1; } catch { } } else { context[DbCountKey] = (int)context[DbCountKey] + 1; } }) // Afterwards clean up our resources .AfterExpansion((destinationObject, sourceObject, context) => { if (context.ContainsKey(DbKey)) { // If the reference count goes to 0, destroy the context var decrementedReferenceCount = (int)context[DbCountKey] - 1; if (decrementedReferenceCount == 0) { (context[DbKey] as IDisposable).Dispose(); context.Remove(DbKey); context.Remove(DbCountKey); } else { context[DbCountKey] = decrementedReferenceCount; } } }); // Now, find all navigation properties on this type and configure each one to load from the database if // actually requested for expansion using (DbContext db = ConstructDbContextWithOptions(optionsBuilder)) { foreach (var prop in typeof(TSourceType).GetNavigationReferenceProperties(db)) { definition.PrepareProperty(prop.Name, (destinationObject, destinationProperty, sourceObject, context) => { if (context.ContainsKey(DbKey)) { var expandDb = context[DbKey] as TContext; expandDb.Attach(sourceObject as TSourceType); expandDb.Entry(sourceObject as TSourceType).Reference(prop.Name).Load(); } }); } foreach (var prop in typeof(TSourceType).GetNavigationCollectionProperties(db)) { definition.PrepareProperty(prop.Name, (destinationObject, destinationProperty, sourceObject, context) => { if (context.ContainsKey(DbKey)) { var expandDb = context[DbKey] as TContext; expandDb.Attach(sourceObject as TSourceType); expandDb.Entry(sourceObject as TSourceType).Collection(prop.Name).Load(); } }); } } })); }