/// <summary> /// Maps the next object from Dapper, from a list of fields. /// </summary> /// <typeparam name="TItemType">The item type to be mapped.</typeparam> /// <param name="context">The context used to map object from Dapper.</param> /// <param name="fieldNames">The GraphQL fields associated with the item.</param> /// <param name="entityMapper">An optional entity mapper. This is used to map complex objects from Dapper mapping results.</param> /// <returns>The mapped item.</returns> public static TItemType Next <TItemType>( this EntityMapContext context, IEnumerable <string> fieldNames, IEntityMapper <TItemType> entityMapper = null) where TItemType : class { return(context.Next <TItemType>( fieldNames, (currentSelectionSet, selectionSet) => selectionSet, entityMapper )); }
/// <summary> /// Maps the next object from Dapper. /// </summary> /// <typeparam name="TItemType">The item type to be mapped.</typeparam> /// <param name="context">The context used to map object from Dapper.</param> /// <param name="fieldName">The name of the GraphQL field associated with the item.</param> /// <param name="entityMapper">An optional entity mapper. This is used to map complex objects from Dapper mapping results.</param> /// <returns>The mapped item.</returns> public static TItemType Next <TItemType>( this EntityMapContext context, string fieldName, IEntityMapper <TItemType> entityMapper = null) where TItemType : class { return(context.Next <TItemType>( new[] { fieldName }, (currentSelectionSet, selectionSet) => currentSelectionSet[fieldName], entityMapper )); }
/// <summary> /// Maps a row of data to an entity. /// </summary> /// <param name="context">A context that contains information used to map Dapper objects.</param> /// <returns>The mapped entity, or null if the entity has previously been returned.</returns> public virtual TEntityType Map(EntityMapContext context) { if (PrimaryKey == null) { throw new InvalidOperationException("PrimaryKey selector is not defined, but is required to use DeduplicatingEntityMapper."); } // Deduplicate the top object (entity) in the list if (context.Items != null && context.Items.Any()) { if (context.Items.First() is TEntityType entity) { var previous = entity; var primaryKey = PrimaryKey(entity); if (primaryKey == null) { throw new InvalidOperationException("A null primary key was provided, which results in an unpredictable state."); } // Deduplicate the entity using available information entity = Deduplicate(entity, primaryKey); if (!object.ReferenceEquals(previous, entity)) { context.Items = new[] { entity }.Concat(context.Items.Skip(1)); } // Map the object var next = Mapper.Map(context); // Return null if we are returning a duplicate object. // Queries can filter out null entries to prevent duplicates. if (ReturnsNullWithDuplicates && KeyCache.ContainsKey(primaryKey)) { return(null); } // Cache a reference to the entity KeyCache[primaryKey] = next; // And, return it return(next); } } return(default(TEntityType)); }
/// <summary> /// Maps the next object from an inline fragment. /// </summary> /// <typeparam name="TItemType">The item type to be mapped.</typeparam> /// <param name="context">The context used to map object from Dapper.</param> /// <param name="fieldName">The GraphQL field that contains the inline fragment(s).</param> /// <param name="entityMapper">An optional entity mapper. This is used to map complex objects from Dapper mapping results.</param> /// <returns>The mapped item.</returns> public static TItemType NextFragment <TItemType>( this EntityMapContext context, string fieldName, IEntityMapper <TItemType> entityMapper = null) where TItemType : class { return(context.Next <TItemType>( new[] { fieldName }, (currentSelectionSet, selectionSet) => currentSelectionSet[fieldName] .SelectionSet .Selections .OfType <InlineFragment>() .Where(f => f.Type.Name == typeof(TItemType).Name) .FirstOrDefault(), entityMapper )); }
/// <summary> /// Maps the next object from Dapper. /// </summary> /// <typeparam name="TItemType">The item type to be mapped.</typeparam> /// <param name="context">The context used to map object from Dapper.</param> /// <param name="fieldNames">The names of one or more GraphQL fields associated with the item.</param> /// <param name="entityMapper">An optional entity mapper. This is used to map complex objects from Dapper mapping results.</param> /// <returns>The mapped item.</returns> public TItemType Next <TItemType>( IEnumerable <string> fieldNames, Func <IDictionary <string, Field>, IHaveSelectionSet, IHaveSelectionSet> getSelectionSet, IEntityMapper <TItemType> entityMapper = null) where TItemType : class { if (fieldNames == null) { throw new ArgumentNullException(nameof(fieldNames)); } if (ItemEnumerator == null || SplitOnEnumerator == null) { throw new NotSupportedException("Cannot call Next() before calling Start()"); } lock (LockObject) { var keys = fieldNames.Intersect(CurrentSelectionSet.Keys); if (keys.Any()) { TItemType item = default(TItemType); while ( ItemEnumerator.MoveNext() && SplitOnEnumerator.MoveNext()) { // Whether a non-null object exists at this position or not, // the SplitOn is expecting this type here, so we will yield it. if (SplitOnEnumerator.Current == typeof(TItemType)) { item = ItemEnumerator.Current as TItemType; break; } } if (entityMapper != null) { // Determine where the next entity mapper will get its selection set from IHaveSelectionSet selectionSet = getSelectionSet(CurrentSelectionSet, SelectionSet); var nextContext = new EntityMapContext { Items = Items.Skip(MappedCount), SelectionSet = selectionSet, SplitOn = SplitOn.Skip(MappedCount), }; using (nextContext) { item = entityMapper.Map(nextContext); // Update enumerators to skip past items already mapped var mappedCount = nextContext.MappedCount; MappedCount += nextContext.MappedCount; int i = 0; while ( // Less 1, the next time we iterate we // will advance by 1 as part of the iteration. i < mappedCount - 1 && ItemEnumerator.MoveNext() && SplitOnEnumerator.MoveNext()) { i++; } } } else { MappedCount++; } return(item); } } return(default(TItemType)); }
public virtual TEntityType Map(EntityMapContext context) { var entity = context.Start <TEntityType>(); return(entity); }
/// <summary> /// Maps a row of data to an entity. /// </summary> /// <param name="context">A context that contains information used to map Dapper objects.</param> /// <returns>The mapped entity, or null if the entity has previously been returned.</returns> public abstract TEntityType Map(EntityMapContext context);