public static Link Last(ReadStreamPage page, ReadStreamOperation operation)
 => new Link(
     Constants.Relations.Last,
     LinkFormatter.FormatBackwardLink(
         page.StreamId,
         operation.MaxCount,
         StreamVersion.End,
         operation.EmbedPayload));
 public static Link Next(ReadStreamPage page, ReadStreamOperation operation)
 => new Link(
     Constants.Relations.Next,
     LinkFormatter.FormatForwardLink(
         page.StreamId,
         operation.MaxCount,
         page.Messages.Max(m => m.StreamVersion) + 1,
         operation.EmbedPayload));
 public static Link Previous(ReadStreamPage page, ReadStreamOperation operation)
 => new Link(
     Constants.Relations.Previous,
     LinkFormatter.FormatBackwardLink(
         page.StreamId,
         operation.MaxCount,
         page.Messages.Min(m => m.StreamVersion) - 1,
         operation.EmbedPayload));
        public async Task <Response> GetPage(ReadStreamOperation operation, CancellationToken cancellationToken)
        {
            var page = await operation.Invoke(_streamStore, cancellationToken);

            var streamMessages = page.Messages.OrderByDescending(m => m.Position).ToArray();

            var payloads = await Task.WhenAll(streamMessages
                                              .Select(message => operation.EmbedPayload
                    ? message.GetJsonData(cancellationToken)
                    : Task.FromResult <string>(null))
                                              .ToArray());

            return(new Response(
                       new HALResponse(new
            {
                page.LastStreamVersion,
                page.LastStreamPosition,
                page.FromStreamVersion,
                page.NextStreamVersion,
                page.IsEnd
            })
                       .AddLinks(Links.Self(operation))
                       .AddLinks(Links.Navigation(page, operation))
                       .AddLinks(Links.Feed(operation))
                       .AddLinks(Links.Metadata(operation))
                       .AddEmbeddedCollection(
                           Constants.Relations.Message,
                           streamMessages.Zip(
                               payloads,
                               (message, payload) => new HALResponse(new
            {
                message.MessageId,
                message.CreatedUtc,
                message.Position,
                message.StreamId,
                message.StreamVersion,
                message.Type,
                payload,
                metadata = message.JsonMetadata
            })
                               .AddLinks(Links.Message.Self(message)))),
                       page.Status == PageReadStatus.StreamNotFound ? 404 : 200));
        }
            public static IEnumerable <Link> Navigation(ReadStreamPage page, ReadStreamOperation operation)
            {
                var first = First(page, operation);

                var last = Last(page, operation);

                yield return(first);

                if (operation.Self != first.Href && !page.IsEnd)
                {
                    yield return(Previous(page, operation));
                }

                if (operation.Self != last.Href && !page.IsEnd)
                {
                    yield return(Next(page, operation));
                }

                yield return(last);
            }
 public static Link Metadata(ReadStreamOperation operation)
 => new Link(
     Constants.Relations.Metadata,
     $"{operation.StreamId}/metadata");
 public static Link Feed(ReadStreamOperation operation)
 => new Link(Constants.Relations.Feed, operation.Self);
 public static Link Self(ReadStreamOperation operation) => new Link(
     Constants.Relations.Self,
     operation.Self);
        public async Task <Response> Get(ReadStreamOperation operation, CancellationToken cancellationToken)
        {
            if (!operation.IsUriCanonical)
            {
                return(new Response(new HALResponse(null), 308)
                {
                    Headers = { [Constants.Headers.Location] = new[] { operation.Self } }
                });
            }

            var page = await operation.Invoke(_streamStore, cancellationToken);

            var streamMessages = page.Messages.OrderByDescending(m => m.Position).ToArray();

            var payloads = await Task.WhenAll(
                Array.ConvertAll(
                    streamMessages,
                    message => operation.EmbedPayload
                        ? message.GetJsonData(cancellationToken)
                        : SkippedPayload.Instance));

            var response = new Response(
                new HALResponse(new
            {
                page.LastStreamVersion,
                page.LastStreamPosition,
                page.FromStreamVersion,
                page.NextStreamVersion,
                page.IsEnd
            })
                .AddLinks(Links.Self(operation))
                .AddLinks(Links.Navigation(page, operation))
                .AddLinks(Links.Feed(operation))
                .AddLinks(Links.Metadata(operation))
                .AddLinks(Links.Index())
                .AddLinks(Links.Find())
                .AddEmbeddedResource(
                    Constants.Relations.AppendToStream,
                    Schemas.AppendToStream)
                .AddEmbeddedResource(
                    Constants.Relations.Delete,
                    Schemas.DeleteStream)
                .AddEmbeddedCollection(
                    Constants.Relations.Message,
                    streamMessages.Zip(
                        payloads,
                        (message, payload) => new HALResponse(new
            {
                message.MessageId,
                message.CreatedUtc,
                message.Position,
                message.StreamId,
                message.StreamVersion,
                message.Type,
                payload,
                metadata = message.JsonMetadata
            })
                        .AddLinks(
                            Links.Message.Self(message),
                            Links.Message.Feed(message)))),
                page.Status == PageReadStatus.StreamNotFound ? 404 : 200);

            if (page.TryGetETag(out var eTag))
            {
                response.Headers.Add(eTag);
            }

            return(response);
        }