From 4376e1fc098784457d43582d60e7c81b3a274f87 Mon Sep 17 00:00:00 2001 From: pjurewicz Date: Thu, 21 Mar 2024 23:02:22 +0100 Subject: [PATCH] Add total events counter to the debug page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ɓukasz Reszke --- ruby_event_store-browser/elm/src/Api.elm | 25 +++++++++++- ruby_event_store-browser/elm/src/Main.elm | 21 ++++++++-- .../elm/src/Page/Debug.elm | 38 +++++++++++++------ .../lib/ruby_event_store/browser.rb | 1 + .../lib/ruby_event_store/browser/app.rb | 6 ++- .../lib/ruby_event_store/browser/get_stats.rb | 27 +++++++++++++ .../spec/api/stats_spec.rb | 16 ++++++++ 7 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 ruby_event_store-browser/lib/ruby_event_store/browser/get_stats.rb create mode 100644 ruby_event_store-browser/spec/api/stats_spec.rb diff --git a/ruby_event_store-browser/elm/src/Api.elm b/ruby_event_store-browser/elm/src/Api.elm index 6ed645f59a..4296e7db1c 100644 --- a/ruby_event_store-browser/elm/src/Api.elm +++ b/ruby_event_store-browser/elm/src/Api.elm @@ -1,9 +1,9 @@ -module Api exposing (Event, PaginatedList, PaginationLink, PaginationLinks, RemoteResource(..), SearchStream, Stream, emptyPaginatedList, eventDecoder, eventsDecoder, getEvent, getEvents, getSearchStreams, getStream, searchStreamsDecoder) +module Api exposing (Event, PaginatedList, PaginationLink, PaginationLinks, RemoteResource(..), SearchStream, Stream, emptyPaginatedList, eventDecoder, eventsDecoder, getEvent, getEvents, getSearchStreams, getStream, searchStreamsDecoder, Stats, getStats) import Flags exposing (Flags) import Http import Iso8601 -import Json.Decode exposing (Decoder, field, list, maybe, string, succeed, value) +import Json.Decode exposing (Decoder, field, list, maybe, string, succeed, value, int) import Json.Decode.Pipeline exposing (optional, optionalAt, required, requiredAt) import Json.Encode exposing (encode) import Maybe.Extra @@ -42,6 +42,9 @@ type alias SearchStream = { streamId : String } +type alias Stats = + { eventsInTotal: Int + } type alias PaginatedList a = { pagination : Pagination.Specification @@ -93,6 +96,9 @@ searchStreamsUrl : Flags -> String -> String searchStreamsUrl flags query = buildUrl (Url.toString flags.apiUrl ++ "/search_streams") query +getStatsUrl : Flags -> String +getStatsUrl flags = + Url.toString flags.apiUrl ++ "/stats" getEvent : (Result Http.Error Event -> msg) -> Flags -> String -> Cmd msg getEvent msgBuilder flags eventId = @@ -117,6 +123,12 @@ getSearchStreams msgBuilder flags query = , expect = Http.expectJson msgBuilder searchStreamsDecoder } +getStats : (Result Http.Error (Stats) -> msg) -> Flags -> Cmd msg +getStats msgBuilder flags = + Http.get + { url = getStatsUrl flags + , expect = Http.expectJson msgBuilder statsDecoder + } eventDecoder : Decoder Event eventDecoder = @@ -183,6 +195,15 @@ searchStreamsDecoder = list searchStreamDecoder |> field "data" +statsDecoder : Decoder Stats +statsDecoder = + statsDecoder_ + |> field "meta" + +statsDecoder_ : Decoder Stats +statsDecoder_ = + succeed Stats + |> required "events_in_total" int linksDecoder : Decoder PaginationLinks linksDecoder = diff --git a/ruby_event_store-browser/elm/src/Main.elm b/ruby_event_store-browser/elm/src/Main.elm index d25672d087..348632b958 100644 --- a/ruby_event_store-browser/elm/src/Main.elm +++ b/ruby_event_store-browser/elm/src/Main.elm @@ -11,6 +11,7 @@ import LinkedTimezones exposing (mapLinkedTimeZone) import Page.Debug import Page.ShowEvent import Page.ShowStream +import Page.Debug import Route import Task import Time @@ -51,7 +52,7 @@ type Msg | GotShowEventMsg Page.ShowEvent.Msg | GotShowStreamMsg Page.ShowStream.Msg | ReceiveTimeZone (Result String Time.ZoneName) - + | GotDebugMsg Page.Debug.Msg type Page = NotFound @@ -131,6 +132,16 @@ update msg model = , Cmd.map GotShowEventMsg subCmd ) + ( GotDebugMsg gotDebugMsg, Debug debugModel ) -> + let + (subModel, subCmd) = + Page.Debug.update gotDebugMsg debugModel + in + ({model | page = Debug subModel} + , Cmd.map GotDebugMsg subCmd + ) + + ( GotLayoutMsg layoutMsg, _ ) -> case model.flags of Nothing -> @@ -215,8 +226,12 @@ navigate model location = Nothing -> ( { model | page = NotFound }, Cmd.none ) - Just Route.Debug -> - ( { model | page = Debug (Page.Debug.init flags) }, Cmd.none ) + Just (Route.Debug) -> + let + page = Page.Debug.init flags + cmd = Page.Debug.initCmd flags + in + ( { model | page = Debug page }, Cmd.map GotDebugMsg cmd ) Nothing -> ( { model | page = NotFound }, Cmd.none ) diff --git a/ruby_event_store-browser/elm/src/Page/Debug.elm b/ruby_event_store-browser/elm/src/Page/Debug.elm index c5cf926cdc..db3fa8d655 100644 --- a/ruby_event_store-browser/elm/src/Page/Debug.elm +++ b/ruby_event_store-browser/elm/src/Page/Debug.elm @@ -1,21 +1,37 @@ module Page.Debug exposing (..) -import Flags exposing (Flags) import Html exposing (..) +import Flags exposing (Flags) +import Api exposing (getStats, Stats) +import Http +type alias Model = { resVersion : String, repositoryAdapter : String, eventsInTotal : String } -type alias Model = - { resVersion : String, repositoryAdapter : String } - +type Msg + = GotStats (Result Http.Error Stats) init : Flags -> Model -init flags = - { resVersion = flags.resVersion, repositoryAdapter = flags.repositoryAdapter } +init flags = + { resVersion = flags.resVersion, repositoryAdapter = flags.repositoryAdapter, eventsInTotal = "" } +initCmd : Flags -> Cmd Msg +initCmd flags = + getStats GotStats flags -view : Model -> Html a +view: Model -> Html a view model = - div [] - [ p [] [ text ("RubyEventStore version: " ++ model.resVersion) ] - , p [] [ text ("RubyEventStore adapter: " ++ model.repositoryAdapter) ] - ] + div [] [ + p [] [text ("RubyEventStore version: " ++ model.resVersion)], + p [] [text ("RubyEventStore adapter: " ++ model.repositoryAdapter)], + p [] [text ("Events in total: " ++ model.eventsInTotal)] + ] + +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = + case msg of + GotStats result -> + case result of + Ok stats -> + ({ model | eventsInTotal = String.fromInt stats.eventsInTotal }, Cmd.none) + Err _ -> + (model, Cmd.none) \ No newline at end of file diff --git a/ruby_event_store-browser/lib/ruby_event_store/browser.rb b/ruby_event_store-browser/lib/ruby_event_store/browser.rb index 8b73ff80d2..586eafe817 100644 --- a/ruby_event_store-browser/lib/ruby_event_store/browser.rb +++ b/ruby_event_store-browser/lib/ruby_event_store/browser.rb @@ -17,3 +17,4 @@ module Browser require_relative "browser/urls" require_relative "browser/gem_source" require_relative "browser/router" +require_relative "browser/get_stats" \ No newline at end of file diff --git a/ruby_event_store-browser/lib/ruby_event_store/browser/app.rb b/ruby_event_store-browser/lib/ruby_event_store/browser/app.rb index af6d495578..022c8515be 100644 --- a/ruby_event_store-browser/lib/ruby_event_store/browser/app.rb +++ b/ruby_event_store-browser/lib/ruby_event_store/browser/app.rb @@ -100,7 +100,11 @@ def call(env) stream_name: params.fetch("stream_name"), ) end - + router.add_route("GET", "/api/stats") do + json GetStats.new( + event_store: event_store + ) + end %w[/ /events/:event_id /streams/:stream_name /debug].each do |starting_route| router.add_route("GET", starting_route) do |_, urls| erb bootstrap_html, diff --git a/ruby_event_store-browser/lib/ruby_event_store/browser/get_stats.rb b/ruby_event_store-browser/lib/ruby_event_store/browser/get_stats.rb new file mode 100644 index 0000000000..9048eda6f4 --- /dev/null +++ b/ruby_event_store-browser/lib/ruby_event_store/browser/get_stats.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module RubyEventStore + module Browser + class GetStats + def initialize(event_store:) + @event_store = event_store + end + + def to_h + { + meta: { + events_in_total: events + } + } + end + + private + + def events + event_store.read.count + end + + attr_reader :event_store + end + end +end diff --git a/ruby_event_store-browser/spec/api/stats_spec.rb b/ruby_event_store-browser/spec/api/stats_spec.rb new file mode 100644 index 0000000000..881a228a5e --- /dev/null +++ b/ruby_event_store-browser/spec/api/stats_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require "spec_helper" + +module RubyEventStore + ::RSpec.describe Browser do + include Browser::IntegrationHelpers + + specify "not existing" do + api_client.get "/api/stats" + expect(api_client.parsed_body["meta"]).to match({ + "events_in_total" => 0 + }) + end + end +end