Ejemplo n.º 1
0
 /// <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
                ));
 }
Ejemplo n.º 2
0
 /// <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));
        }
Ejemplo n.º 4
0
 /// <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
                ));
 }
Ejemplo n.º 5
0
        /// <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));
        }
Ejemplo n.º 6
0
        public virtual TEntityType Map(EntityMapContext context)
        {
            var entity = context.Start <TEntityType>();

            return(entity);
        }
Ejemplo n.º 7
0
 /// <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);