File size: 1,450 Bytes
8da2481
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
defmodule Plausible.Shield.HostnameRuleCache do
  @moduledoc """
  Allows retrieving Hostname Rules by domain
  """
  alias Plausible.Shield.HostnameRule

  import Ecto.Query
  use Plausible.Cache

  @cache_name :hostname_allowlist_by_domain

  @cached_schema_fields ~w(
    id
    hostname_pattern
    action
  )a

  @impl true
  def name(), do: @cache_name

  @impl true
  def child_id(), do: :cache_hostname_blocklist

  @impl true
  def count_all() do
    Plausible.Repo.aggregate(HostnameRule, :count)
  end

  @impl true
  def base_db_query() do
    from rule in HostnameRule,
      inner_join: s in assoc(rule, :site),
      select: {
        s.domain,
        s.domain_changed_from,
        %{struct(rule, ^@cached_schema_fields) | from_cache?: true}
      }
  end

  @impl true
  def get_from_source(domain) do
    query =
      base_db_query()
      |> where([..., site], site.domain == ^domain)

    case Plausible.Repo.all(query) do
      [_ | _] = results ->
        Enum.map(results, fn {_, _, rule = %HostnameRule{}} ->
          %HostnameRule{rule | from_cache?: false}
        end)

      _ ->
        nil
    end
  end

  @impl true
  def unwrap_cache_keys(items) do
    Enum.reduce(items, [], fn
      {domain, nil, object}, acc ->
        [{domain, object} | acc]

      {domain, domain_changed_from, object}, acc ->
        [
          {domain, object},
          {domain_changed_from, object} | acc
        ]
    end)
  end
end