• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

danielberkompas / cloak_ecto / 9355b38e-5636-4248-94b5-6129115c3d91

12 May 2025 11:21AM UTC coverage: 91.818% (-6.1%) from 97.917%
9355b38e-5636-4248-94b5-6129115c3d91

Pull #58

semaphore

web-flow
Merge 85b0d35a6 into 9989e732c
Pull Request #58: fix: Ecto.Enum type wrapped in tuple

0 of 2 new or added lines in 1 file covered. (0.0%)

6 existing lines in 3 files now uncovered.

101 of 110 relevant lines covered (91.82%)

148.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.83
/lib/cloak_ecto/migrator/cursor_stream.ex
1
defmodule Cloak.Ecto.Migrator.CursorStream do
2
  @moduledoc false
3
  # Returns a stream of primary key values from a database table associated
4
  # with an Ecto.Schema.
5
  #
6
  # By default, uses the primary key as the cursor. Users can specify a
7
  # custom list of cursor fields using the Cloak.CustomCursor behaviour.
8

9
  import Ecto.Query
10

11
  def new(repo, schema, limit) do
12
    Stream.resource(
8✔
13
      fn ->
14
        [primary_key | _] = schema.__schema__(:primary_key)
8✔
15
        cursor_fields = fields_for_cursor(schema, primary_key)
8✔
16

17
        select_fields =
8✔
18
          [primary_key]
19
          |> Enum.concat(cursor_fields)
20
          |> Enum.uniq()
21

22
        query =
8✔
23
          schema
24
          |> select(^select_fields)
25
          |> order_by(^cursor_fields)
26

27
        cursor_record =
8✔
28
          query
29
          |> first()
30
          |> repo.one()
31

32
        %{
8✔
33
          results: [Map.get(cursor_record, primary_key)],
34
          repo: repo,
35
          schema: schema,
36
          query: query,
37
          cursor: Map.take(cursor_record, cursor_fields),
38
          cursor_fields: cursor_fields,
39
          primary_key: primary_key,
40
          limit: limit
41
        }
42
      end,
43
      &next/1,
44
      fn _config -> :ok end
8✔
45
    )
46
  end
47

UNCOV
48
  defp next(%{cursor: nil} = config) do
×
49
    {:halt, config}
50
  end
51

52
  defp next(%{results: [head | tail]} = config) do
1,492✔
53
    {[head], %{config | results: tail}}
54
  end
55

56
  defp next(%{results: []} = config) do
57
    results =
23✔
58
      config
59
      |> query_by_cursor()
60
      |> limit(^config.limit)
23✔
61
      |> config.repo.all()
23✔
62

63
    case length(results) do
23✔
64
      0 ->
8✔
65
        {:halt, config}
66

67
      _ ->
68
        new_cursor =
15✔
69
          results
70
          |> List.last()
71
          |> Map.take(config.cursor_fields)
15✔
72

73
        [head | tail] = Enum.map(results, &Map.get(&1, config.primary_key))
15✔
74
        {[head], %{config | cursor: new_cursor, results: tail}}
75
    end
76
  end
77

78
  defp fields_for_cursor(schema, primary_key) do
79
    if function_exported?(schema, :__cloak_cursor_fields__, 0) do
8✔
80
      schema.__cloak_cursor_fields__
1✔
81
    else
82
      [primary_key]
83
    end
84
  end
85

86
  defp query_by_cursor(config) do
87
    Enum.reduce(config.cursor_fields, config.query, fn field, query ->
23✔
88
      cursor_filter(query, field, config.schema.__schema__(:type, field), config.cursor[field])
29✔
89
    end)
90
  end
91

92
  defp cursor_filter(query, field, type, value)
93
       when type in [:utc_datetime, :naive_datetime, :date, :time] do
94
    where(query, [s], field(s, ^field) >= ^value)
6✔
95
  end
96

97
  defp cursor_filter(query, field, _type, value) do
98
    where(query, [s], field(s, ^field) > ^value)
23✔
99
  end
100
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc