Skip to content

Commit 4b340f3

Browse files
committed
Dodge MultiValidation.result in resource#details
1 parent 6140761 commit 4b340f3

19 files changed

+258
-70
lines changed

apps/transport/lib/db/multi_validation.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ defmodule DB.MultiValidation do
2929

3030
has_one(:metadata, DB.ResourceMetadata)
3131
timestamps(type: :utc_datetime_usec)
32+
33+
field(:digest, :map)
3234
end
3335

3436
def base_query(opts \\ []) do

apps/transport/lib/transport_web/controllers/resource_controller.ex

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ defmodule TransportWeb.ResourceController do
2323
not_found(conn)
2424

2525
resource ->
26-
validation = latest_validation(resource)
26+
validation = latest_validation(resource, include_result: not prefer_digest?(resource))
2727

2828
conn =
2929
conn
@@ -46,6 +46,12 @@ defmodule TransportWeb.ResourceController do
4646
end
4747
end
4848

49+
defp prefer_digest?(%Resource{} = resource) do
50+
Resource.gtfs?(resource) || Resource.netex?(resource)
51+
end
52+
53+
defp default_params?(params), do: Map.keys(params) == ["id"]
54+
4955
defp not_found(conn) do
5056
conn
5157
|> put_status(:not_found)
@@ -136,7 +142,7 @@ defmodule TransportWeb.ResourceController do
136142

137143
defp put_resource_flash(conn, _), do: conn
138144

139-
defp latest_validation(%Resource{id: resource_id} = resource) do
145+
defp latest_validation(%Resource{id: resource_id} = resource, opts) do
140146
validators = resource |> Transport.ValidatorsSelection.validators() |> Enum.filter(&(&1 in @enabled_validators))
141147

142148
validator =
@@ -145,15 +151,15 @@ defmodule TransportWeb.ResourceController do
145151
Enum.empty?(validators) -> nil
146152
end
147153

148-
DB.MultiValidation.resource_latest_validation(resource_id, validator, include_result: true)
154+
DB.MultiValidation.resource_latest_validation(resource_id, validator, opts)
149155
end
150156

151157
def render_details(conn, resource) do
152158
conn |> assign(:resource, resource) |> render("details.html")
153159
end
154160

155161
defp render_gtfs_details(conn, params, resource, validation) do
156-
validation_details = {_, _, _, _, issues} = build_gtfs_validation_details(validation, params)
162+
validation_details = {_, _, _, _, issues} = build_gtfs_validation_details(resource, validation, params)
157163

158164
issue_type =
159165
case params["issue_type"] do
@@ -168,19 +174,47 @@ defmodule TransportWeb.ResourceController do
168174
|> render("gtfs_details.html")
169175
end
170176

171-
defp build_gtfs_validation_details(nil, _params), do: {nil, nil, nil, [], []}
177+
defp build_gtfs_validation_details(_resource, nil, _params), do: {nil, nil, nil, [], []}
178+
179+
defp build_gtfs_validation_details(
180+
%DB.Resource{} = resource,
181+
%{digest: nil, metadata: metadata = %DB.ResourceMetadata{}},
182+
params
183+
) do
184+
# Notably useful if digest wasn't persisted yet
185+
186+
%DB.MultiValidation{result: validation_result} = latest_validation(resource, include_result: true)
187+
188+
%{"summary" => summary, "stats" => stats} =
189+
Transport.Validators.GTFSTransport.digest(validation_result)
172190

173-
defp build_gtfs_validation_details(%{result: validation_result, metadata: metadata = %DB.ResourceMetadata{}}, params) do
174-
summary = Transport.Validators.GTFSTransport.summary(validation_result)
175-
stats = Transport.Validators.GTFSTransport.count_by_severity(validation_result)
176191
issues = Transport.Validators.GTFSTransport.get_issues(validation_result, params)
177192

178193
{summary, stats, metadata.metadata, metadata.modes, issues}
179194
end
180195

196+
defp build_gtfs_validation_details(
197+
%DB.Resource{} = resource,
198+
%{digest: digest, metadata: metadata = %DB.ResourceMetadata{}},
199+
params
200+
) do
201+
%{"summary" => summary, "stats" => stats, "issues" => issues} = digest
202+
203+
issues =
204+
if default_params?(params) do
205+
issues
206+
else
207+
%DB.MultiValidation{result: validation_result} = latest_validation(resource, include_result: true)
208+
209+
Transport.Validators.GTFSTransport.get_issues(validation_result, params)
210+
end
211+
212+
{summary, stats, metadata.metadata, metadata.modes, issues}
213+
end
214+
181215
defp render_netex_details(conn, params, resource, validation) do
182216
{results_adapter, validation_details, errors_template, max_severity} =
183-
build_netex_validation_details(validation, params)
217+
build_netex_validation_details(resource, validation, params)
184218

185219
conn
186220
|> assign_base_resource_details(params, resource, validation_details)
@@ -191,18 +225,43 @@ defmodule TransportWeb.ResourceController do
191225
|> render("netex_details.html")
192226
end
193227

194-
defp build_netex_validation_details(nil, _params), do: {nil, {nil, nil, nil, [], []}, nil, nil}
228+
defp build_netex_validation_details(_resource, nil, _params), do: {nil, {nil, nil, nil, [], []}, nil, nil}
195229

196230
defp build_netex_validation_details(
197-
%{validator_version: version, result: validation_result, metadata: metadata = %DB.ResourceMetadata{}},
231+
%DB.Resource{} = resource,
232+
%{validator_version: version, digest: nil, metadata: metadata = %DB.ResourceMetadata{}},
198233
params
199234
) do
235+
# Notably useful if digest wasn't persisted yet
236+
%DB.MultiValidation{result: validation_result} = latest_validation(resource, include_result: true)
237+
results_adapter = Transport.Validators.NeTEx.ResultsAdapter.resolve(version)
238+
digest = results_adapter.digest(validation_result)
239+
240+
build_netex_validation_details(resource, version, digest, metadata, params)
241+
end
242+
243+
defp build_netex_validation_details(
244+
resource,
245+
%{validator_version: version, digest: digest, metadata: metadata = %DB.ResourceMetadata{}},
246+
params
247+
) do
248+
build_netex_validation_details(resource, version, digest, metadata, params)
249+
end
250+
251+
defp build_netex_validation_details(resource, version, digest, metadata, params) do
252+
%{"summary" => summary, "stats" => stats, "max_severity" => max_severity} = digest
200253
results_adapter = Transport.Validators.NeTEx.ResultsAdapter.resolve(version)
201-
summary = results_adapter.summary(validation_result)
202-
stats = results_adapter.count_by_severity(validation_result)
203-
issues = results_adapter.get_issues(validation_result, params)
204254
errors_template = pick_netex_errors_template(version)
205-
max_severity = results_adapter.count_max_severity(validation_result)
255+
256+
issues =
257+
if default_params?(params) do
258+
digest["issues"]
259+
else
260+
# Digest doesn't include issues for non default params
261+
%DB.MultiValidation{result: validation_result} = latest_validation(resource, include_result: true)
262+
263+
results_adapter.get_issues(validation_result, params)
264+
end
206265

207266
{results_adapter, {summary, stats, metadata.metadata, metadata.modes, issues}, errors_template, max_severity}
208267
end

apps/transport/lib/transport_web/templates/dataset/_resource_validation_summary_netex.html.heex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div class="pb-24">
33
<% link = resource_path(@conn, :details, @resource.id) <> "#validation-report" %>
44
<% results_adapter = Transport.Validators.NeTEx.ResultsAdapter.resolve(@validation.validator_version) %>
5-
<% {severity, count} = results_adapter.count_max_severity(@validation.result) %>
5+
<% %{"max_level" => severity, "worst_occurrences" => count} = results_adapter.count_max_severity(@validation.result) %>
66
<a href={link}>
77
<span class={summary_class(%{severity: String.capitalize(severity), count_errors: count})}>
88
<%= if results_adapter.no_error?(severity) do %>

apps/transport/lib/transport_web/templates/resource/_netex_validation_errors_v0_2_x.html.heex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<% {max_level, worst_occurrences} = @max_severity %>
1+
<% %{"max_level" => max_level, "worst_occurrences" => worst_occurrences} = @max_severity %>
22
<% current_category = @conn.params["issues_category"] || "" %>
33

44
<h4><%= @results_adapter.format_severity(max_level, worst_occurrences) |> String.capitalize() %></h4>

apps/transport/lib/transport_web/templates/resource/_validation_summary.html.heex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
<div id="issues" class="validation-navigation">
22
<nav class="issues-list validation" role="navigation">
3-
<%= for {severity, issues} <- @validation_summary do %>
3+
<%= for %{"severity" => severity, "issues" => issues} <- @validation_summary do %>
44
<%= if Map.get(@severities_count, severity, 0) > 0 do %>
55
<div class="validation-issue">
66
<h4><%= @results_adapter.format_severity(severity, @severities_count[severity]) %></h4>
77
<ul>
8-
<%= for {key, issue} <- issues do %>
8+
<%= for %{"key" => key, "issue" => issue} <- issues do %>
99
<li>
10-
<%= if issue.count > 0 do %>
10+
<%= if issue["count"] > 0 do %>
1111
<%= link(
12-
"#{issue.title} (#{issue.count})",
12+
"#{issue["title"]} (#{issue["count"]})",
1313
to:
1414
"#{current_url(@conn, %{"issue_type" => key, "token" => @token} |> Map.reject(fn {_, v} -> is_nil(v) end))}#issues",
1515
class: if(key == @results_adapter.issue_type(@issues.entries), do: "active")

apps/transport/lib/transport_web/templates/validation/show_netex_v0_2_x.html.heex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
<div class="validation-content">
2020
<div id="issues" class="container">
21-
<% {_, worst_occurrences} = @max_severity %>
21+
<% %{"worst_occurrences" => worst_occurrences} = @max_severity %>
2222
<% current_category = @conn.params["issues_category"] || "" %>
2323
<div id="issues" class="validation-navigation">
2424
<nav class="issues-list validation" role="navigation">

apps/transport/lib/transport_web/views/dataset_view.ex

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ defmodule TransportWeb.DatasetView do
238238
def summary_class(%{count_errors: 0}), do: "resource__summary--Success"
239239
def summary_class(%{severity: severity}), do: "resource__summary--#{severity}"
240240

241+
def summary_class(%DB.MultiValidation{digest: %{"errors_count" => errors_count}})
242+
when is_integer(errors_count) and errors_count > 0 do
243+
"resource__summary--Error"
244+
end
245+
246+
def summary_class(%DB.MultiValidation{digest: %{"warnings_count" => warnings_count}})
247+
when is_integer(warnings_count) and warnings_count > 0 do
248+
"resource__summary--Warning"
249+
end
250+
241251
def summary_class(%DB.MultiValidation{result: %{"errors_count" => errors_count}})
242252
when is_integer(errors_count) and errors_count > 0 do
243253
"resource__summary--Error"
@@ -250,13 +260,21 @@ defmodule TransportWeb.DatasetView do
250260

251261
def summary_class(%DB.MultiValidation{}), do: "resource__summary--Success"
252262

263+
def warnings_count(%DB.MultiValidation{digest: %{"warnings_count" => warnings_count}})
264+
when is_integer(warnings_count) and warnings_count >= 0,
265+
do: warnings_count
266+
253267
def warnings_count(%DB.MultiValidation{result: %{"warnings_count" => warnings_count}})
254268
when is_integer(warnings_count) and warnings_count >= 0,
255269
do: warnings_count
256270

257271
def warnings_count(%DB.MultiValidation{validator: @gtfs_rt_validator_name}), do: 0
258272
def warnings_count(%DB.MultiValidation{}), do: nil
259273

274+
def errors_count(%DB.MultiValidation{digest: %{"errors_count" => errors_count}})
275+
when is_integer(errors_count) and errors_count >= 0,
276+
do: errors_count
277+
260278
def errors_count(%DB.MultiValidation{result: %{"errors_count" => errors_count}})
261279
when is_integer(errors_count) and errors_count >= 0,
262280
do: errors_count

apps/transport/lib/transport_web/views/resource_view.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ defmodule TransportWeb.ResourceView do
321321
~H"""
322322
<ul class="summary">
323323
<.netex_errors_category
324-
:for={{category, stats} <- @validation_summary}
324+
:for={%{"category" => category, "stats" => stats} <- @validation_summary}
325325
conn={@conn}
326326
results_adapter={@results_adapter}
327327
category={category}
@@ -357,15 +357,15 @@ defmodule TransportWeb.ResourceView do
357357
defp netex_errors_category(%{conn: _, category: _, stats: _, token: _, results_adapter: _} = assigns) do
358358
~H"""
359359
<li>
360-
<.validity_icon errors={@stats[:count]} />
360+
<.validity_icon errors={@stats["count"]} />
361361
<div class="selector">
362-
<%= compatibility_filter(@conn, @category, @token, @stats[:count]) %>
363-
<.stats :if={@stats[:count] > 0} stats={@stats} results_adapter={@results_adapter} />
362+
<%= compatibility_filter(@conn, @category, @token, @stats["count"]) %>
363+
<.stats :if={@stats["count"] > 0} stats={@stats} results_adapter={@results_adapter} />
364364
</div>
365365
<p :if={netex_category_description(@category)}>
366366
<%= netex_category_description(@category) %>
367367
</p>
368-
<.category_hints :if={netex_category_hints(@category) && @stats[:count] > 0} category={@category} />
368+
<.category_hints :if={netex_category_hints(@category) && @stats["count"] > 0} category={@category} />
369369
</li>
370370
"""
371371
end
@@ -379,7 +379,7 @@ defmodule TransportWeb.ResourceView do
379379

380380
defp stats(%{stats: _, results_adapter: _} = assigns) do
381381
~H"""
382-
(<%= @results_adapter.format_severity(@stats[:criticity], @stats[:count]) %>)
382+
(<%= @results_adapter.format_severity(@stats["criticity"], @stats["count"]) %>)
383383
"""
384384
end
385385

apps/transport/lib/validators/gtfs_transport_validator.ex

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,13 @@ defmodule Transport.Validators.GTFSTransport do
3030
features: find_tags(metadata)
3131
}
3232

33+
result = validation_result(validations)
34+
3335
%DB.MultiValidation{
3436
validation_timestamp: timestamp,
3537
validator: validator_name(),
36-
result: validation_result(validations),
38+
result: result,
39+
digest: digest(result),
3740
data_vis: data_vis,
3841
command: command(url),
3942
resource_history_id: resource_history_id,
@@ -134,8 +137,8 @@ defmodule Transport.Validators.GTFSTransport do
134137
iex> validation_result = %{"tooClose" => [%{"severity" => "Warning"}], "funnyName" => [%{"severity" => "Information"}]}
135138
iex> summary(validation_result)
136139
[
137-
{"Warning", [{"tooClose", %{count: 1, severity: "Warning", title: nil}}]},
138-
{"Information", [{"funnyName", %{count: 1, severity: "Information", title: nil}}]}
140+
%{"severity" => "Warning", "issues" => [%{"key" => "tooClose", "issue" => %{"count" => 1, "severity" => "Warning", "title" => nil}}]},
141+
%{"severity" => "Information", "issues" => [%{"key" => "funnyName", "issue" => %{"count" => 1, "severity" => "Information", "title" => nil}}]}
139142
]
140143
iex> summary(%{})
141144
[]
@@ -146,14 +149,31 @@ defmodule Transport.Validators.GTFSTransport do
146149
|> Enum.map(fn {key, issues} ->
147150
{key,
148151
%{
149-
count: Enum.count(issues),
150-
title: issues_short_translation()[key],
151-
severity: issues |> List.first() |> Map.fetch!("severity")
152+
"count" => Enum.count(issues),
153+
"title" => issues_short_translation()[key],
154+
"severity" => issues |> List.first() |> Map.fetch!("severity")
152155
}}
153156
end)
154-
|> Map.new()
155-
|> Enum.group_by(fn {_, issue} -> issue.severity end)
157+
|> Enum.group_by(fn {_, issue} -> issue["severity"] end)
156158
|> Enum.sort_by(fn {severity, _} -> severity_level(severity) end)
159+
|> Enum.map(fn {severity, issues} ->
160+
%{
161+
"severity" => severity,
162+
"issues" => issues |> Enum.map(fn {key, issue} -> %{"key" => key, "issue" => issue} end)
163+
}
164+
end)
165+
end
166+
167+
@spec digest(map) :: map
168+
def digest(%{} = validation_result) do
169+
summary = Transport.Validators.GTFSTransport.summary(validation_result)
170+
stats = Transport.Validators.GTFSTransport.count_by_severity(validation_result)
171+
172+
%Scrivener.Config{page_size: page_size} = TransportWeb.PaginationHelpers.make_pagination_config(%{})
173+
# Limit to the first page to limit payload size
174+
issues = Transport.Validators.GTFSTransport.get_issues(validation_result, %{}) |> Enum.take(page_size)
175+
176+
%{"summary" => summary, "stats" => stats, "issues" => issues}
157177
end
158178

159179
@doc """

apps/transport/lib/validators/netex/results_adapter.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defmodule Transport.Validators.NeTEx.ResultsAdapter do
66
@callback summary(map()) :: list()
77
@callback count_by_severity(map()) :: map()
88
@callback get_issues(map(), map()) :: list()
9+
@callback digest(map()) :: map()
910
@callback issue_type(list()) :: nil | binary()
1011
@callback format_severity(binary(), non_neg_integer()) :: binary()
1112
@callback count_max_severity(map()) :: {binary(), integer()}

0 commit comments

Comments
 (0)