Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
2.7KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Repo do
  5. use Ecto.Repo,
  6. otp_app: :pleroma,
  7. adapter: Ecto.Adapters.Postgres,
  8. migration_timestamps: [type: :naive_datetime_usec]
  9. import Ecto.Query
  10. require Logger
  11. defmodule Instrumenter, do: use(Prometheus.EctoInstrumenter)
  12. @doc """
  13. Dynamically loads the repository url from the
  14. DATABASE_URL environment variable.
  15. """
  16. def init(_, opts) do
  17. {:ok, Keyword.put(opts, :url, System.get_env("DATABASE_URL"))}
  18. end
  19. @doc "find resource based on prepared query"
  20. @spec find_resource(Ecto.Query.t()) :: {:ok, struct()} | {:error, :not_found}
  21. def find_resource(%Ecto.Query{} = query) do
  22. case __MODULE__.one(query) do
  23. nil -> {:error, :not_found}
  24. resource -> {:ok, resource}
  25. end
  26. end
  27. def find_resource(_query), do: {:error, :not_found}
  28. @doc """
  29. Gets association from cache or loads if need
  30. ## Examples
  31. iex> Repo.get_assoc(token, :user)
  32. %User{}
  33. """
  34. @spec get_assoc(struct(), atom()) :: {:ok, struct()} | {:error, :not_found}
  35. def get_assoc(resource, association) do
  36. case __MODULE__.preload(resource, association) do
  37. %{^association => assoc} when not is_nil(assoc) -> {:ok, assoc}
  38. _ -> {:error, :not_found}
  39. end
  40. end
  41. @doc """
  42. Returns a lazy enumerable that emits all entries from the data store matching the given query.
  43. `returns_as` use to group records. use the `batches` option to fetch records in bulk.
  44. ## Examples
  45. # fetch records one-by-one
  46. iex> Pleroma.Repo.chunk_stream(Pleroma.Activity.Queries.by_actor(ap_id), 500)
  47. # fetch records in bulk
  48. iex> Pleroma.Repo.chunk_stream(Pleroma.Activity.Queries.by_actor(ap_id), 500, :batches)
  49. """
  50. @spec chunk_stream(Ecto.Query.t(), integer(), atom()) :: Enumerable.t()
  51. def chunk_stream(query, chunk_size, returns_as \\ :one, query_options \\ []) do
  52. # We don't actually need start and end functions of resource streaming,
  53. # but it seems to be the only way to not fetch records one-by-one and
  54. # have individual records be the elements of the stream, instead of
  55. # lists of records
  56. Stream.resource(
  57. fn -> 0 end,
  58. fn
  59. last_id ->
  60. query
  61. |> order_by(asc: :id)
  62. |> where([r], r.id > ^last_id)
  63. |> limit(^chunk_size)
  64. |> all(query_options)
  65. |> case do
  66. [] ->
  67. {:halt, last_id}
  68. records ->
  69. last_id = List.last(records).id
  70. if returns_as == :one do
  71. {records, last_id}
  72. else
  73. {[records], last_id}
  74. end
  75. end
  76. end,
  77. fn _ -> :ok end
  78. )
  79. end
  80. end