Skip to content

Commit 5d92258

Browse files
committed
Support myxql (#85)
1 parent 0556cdf commit 5d92258

File tree

17 files changed

+155
-11
lines changed

17 files changed

+155
-11
lines changed

.github/workflows/elixir.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ jobs:
3535
--health-interval 10s
3636
--health-timeout 5s
3737
--health-retries 5
38+
mariadb:
39+
image: mariadb:11
40+
ports: ["3306:3306"]
41+
env:
42+
MARIADB_ROOT_PASSWORD: root
43+
options: >-
44+
--health-cmd "healthcheck.sh --connect --innodb_initialized"
45+
--health-interval 10s
46+
--health-timeout 5s
47+
--health-retries 5
3848
name: Elixir v${{ matrix.elixir }}, Erlang v${{ matrix.erlang }}
3949
steps:
4050
- uses: actions/checkout@v4
@@ -83,3 +93,8 @@ jobs:
8393
run: mix test
8494
env:
8595
DB: postgres
96+
97+
- name: Run Tests - MySQL/MariaDB
98+
run: mix test
99+
env:
100+
DB: mysql

config/dev.example.exs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ config :error_tracker, :ecto_adapter, :postgres
2929
config :error_tracker, ErrorTrackerDev.Repo,
3030
url: "ecto://postgres:postgres@127.0.0.1/error_tracker_dev"
3131

32+
# MySQL/MariaDB adapter
33+
#
34+
# To use MySQL/MariaDB on your local development machine uncomment these lines and
35+
# comment the lines of other adapters.
36+
37+
# config :error_tracker, :ecto_adapter, :mysql
38+
39+
# config :error_tracker, ErrorTrackerDev.Repo,
40+
# url: "ecto://root:root@127.0.0.1/error_tracker_dev"
41+
3242
# SQLite3 adapter
3343
#
3444
# To use SQLite3 on your local development machine uncomment these lines and

config/test.example.exs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ config :error_tracker, ErrorTracker.Test.Repo,
55
pool: Ecto.Adapters.SQL.Sandbox,
66
log: false
77

8+
config :error_tracker, ErrorTracker.Test.MySQLRepo,
9+
url: "ecto://root:root@127.0.0.1/error_tracker_test",
10+
pool: Ecto.Adapters.SQL.Sandbox,
11+
log: false
12+
813
config :error_tracker, ErrorTracker.Test.LiteRepo,
914
database: "priv/lite_repo/test.db",
1015
pool: Ecto.Adapters.SQL.Sandbox,

dev.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Config.Reader.read!("config/config.exs", env: :dev)
1616
adapter =
1717
case Application.get_env(:error_tracker, :ecto_adapter) do
1818
:postgres -> Ecto.Adapters.Postgres
19+
:mysql -> Ecto.Adapters.MyXQL
1920
:sqlite3 -> Ecto.Adapters.SQLite3
2021
end
2122

guides/Getting Started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This guide is an introduction to ErrorTracker, an Elixir-based built-in error tr
44

55
In this guide we will learn how to install ErrorTracker in an Elixir project so you can start reporting errors as soon as possible. We will also cover more advanced topics such as how to report custom errors and how to add extra context to reported errors.
66

7-
**This guide requires you to have set up Ecto with PostgreSQL or SQLite3 beforehand.**
7+
**This guide requires you to have set up Ecto with PostgreSQL, MySQL/MariaDB or SQLite3 beforehand.**
88

99
## Installing ErrorTracker as a dependency
1010

lib/error_tracker.ex

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ defmodule ErrorTracker do
1717
## Requirements
1818
1919
ErrorTracker requires Elixir 1.15+, Ecto 3.11+, Phoenix LiveView 0.19+, and
20-
PostgreSQL or SQLite3 as database.
20+
PostgreSQL, MySQL/MariaDB or SQLite3 as database.
2121
2222
## Integrations
2323
@@ -221,10 +221,18 @@ defmodule ErrorTracker do
221221
{:ok, {error, occurrence}} =
222222
Repo.transaction(fn ->
223223
error =
224-
Repo.insert!(error,
225-
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]],
226-
conflict_target: :fingerprint
227-
)
224+
ErrorTracker.Repo.with_adapter(fn
225+
:mysql ->
226+
Repo.insert!(error,
227+
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]]
228+
)
229+
230+
_other ->
231+
Repo.insert!(error,
232+
on_conflict: [set: [status: :unresolved, last_occurrence_at: DateTime.utc_now()]],
233+
conflict_target: :fingerprint
234+
)
235+
end)
228236

229237
occurrence =
230238
error

lib/error_tracker/migration.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ defmodule ErrorTracker.Migration do
111111
defp migrator do
112112
ErrorTracker.Repo.with_adapter(fn
113113
:postgres -> ErrorTracker.Migration.Postgres
114+
:mysql -> ErrorTracker.Migration.MySQL
114115
:sqlite -> ErrorTracker.Migration.SQLite
115116
adapter -> raise "ErrorTracker does not support #{adapter}"
116117
end)

lib/error_tracker/migration/mysql.ex

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
defmodule ErrorTracker.Migration.MySQL do
2+
@moduledoc false
3+
4+
@behaviour ErrorTracker.Migration
5+
6+
use Ecto.Migration
7+
alias ErrorTracker.Migration.SQLMigrator
8+
9+
@initial_version 3
10+
@current_version 3
11+
12+
@impl ErrorTracker.Migration
13+
def up(opts) do
14+
opts = with_defaults(opts, @current_version)
15+
SQLMigrator.migrate_up(__MODULE__, opts, @initial_version)
16+
end
17+
18+
@impl ErrorTracker.Migration
19+
def down(opts) do
20+
opts = with_defaults(opts, @initial_version)
21+
SQLMigrator.migrate_down(__MODULE__, opts, @initial_version)
22+
end
23+
24+
@impl ErrorTracker.Migration
25+
def current_version(opts) do
26+
opts = with_defaults(opts, @initial_version)
27+
SQLMigrator.current_version(opts)
28+
end
29+
30+
defp with_defaults(opts, version) do
31+
Enum.into(opts, %{version: version})
32+
end
33+
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
defmodule ErrorTracker.Migration.MySQL.V03 do
2+
@moduledoc false
3+
4+
use Ecto.Migration
5+
6+
def up(_opts) do
7+
create table(:error_tracker_meta, primary_key: [name: :key, type: :string]) do
8+
add :value, :string, null: false
9+
end
10+
11+
create table(:error_tracker_errors, primary_key: [name: :id, type: :bigserial]) do
12+
add :kind, :string, null: false
13+
add :reason, :text, null: false
14+
add :source_line, :text, null: false
15+
add :source_function, :text, null: false
16+
add :status, :string, null: false
17+
add :fingerprint, :string, null: false
18+
add :last_occurrence_at, :utc_datetime_usec, null: false
19+
20+
timestamps(type: :utc_datetime_usec)
21+
end
22+
23+
create unique_index(:error_tracker_errors, [:fingerprint])
24+
25+
create table(:error_tracker_occurrences, primary_key: [name: :id, type: :bigserial]) do
26+
add :context, :map, null: false
27+
add :reason, :text, null: false
28+
add :stacktrace, :map, null: false
29+
30+
add :error_id,
31+
references(:error_tracker_errors, on_delete: :delete_all, column: :id, type: :bigserial),
32+
null: false
33+
34+
timestamps(type: :utc_datetime_usec, updated_at: false)
35+
end
36+
37+
create index(:error_tracker_occurrences, [:error_id])
38+
39+
create index(:error_tracker_errors, [:last_occurrence_at])
40+
end
41+
42+
def down(_opts) do
43+
drop table(:error_tracker_occurrences)
44+
drop table(:error_tracker_errors)
45+
drop table(:error_tracker_meta)
46+
end
47+
end

lib/error_tracker/migration/sql_migrator.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ defmodule ErrorTracker.Migration.SQLMigrator do
7373
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value
7474
"""
7575

76+
:mysql ->
77+
execute """
78+
INSERT INTO error_tracker_meta (`key`, value)
79+
VALUES ('migration_version', '#{version}'), ('migration_timestamp', '#{timestamp}')
80+
ON DUPLICATE KEY UPDATE value = VALUES(value)
81+
"""
82+
7683
_other ->
7784
execute """
7885
INSERT INTO error_tracker_meta (key, value)

lib/error_tracker/repo.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ defmodule ErrorTracker.Repo do
4141
adapter =
4242
case repo().__adapter__() do
4343
Ecto.Adapters.Postgres -> :postgres
44+
Ecto.Adapters.MyXQL -> :mysql
4445
Ecto.Adapters.SQLite3 -> :sqlite
4546
end
4647

lib/error_tracker/schemas/occurrence.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ defmodule ErrorTracker.Occurrence do
4444
json_encoder =
4545
ErrorTracker.Repo.with_adapter(fn
4646
:postgres -> Application.get_env(:postgrex, :json_library, Jason)
47+
:mysql -> Application.get_env(:myxql, :json_library, Jason)
4748
:sqlite -> Application.get_env(:ecto_sqlite3, :json_library, Jason)
4849
end)
4950

lib/error_tracker/web/live/dashboard.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ defmodule ErrorTracker.Web.Live.Dashboard do
5959

6060
defp paginate_errors(socket) do
6161
%{page: page, search: search} = socket.assigns
62-
62+
offset = (page - 1) * @per_page
6363
query = filter(Error, search)
6464

6565
total_errors = Repo.aggregate(query, :count)
@@ -68,7 +68,7 @@ defmodule ErrorTracker.Web.Live.Dashboard do
6868
Repo.all(
6969
from query,
7070
order_by: [desc: :last_occurrence_at],
71-
offset: (^page - 1) * @per_page,
71+
offset: ^offset,
7272
limit: @per_page
7373
)
7474

@@ -115,6 +115,7 @@ defmodule ErrorTracker.Web.Live.Dashboard do
115115
# strings. SQLite3 only supports LIKE, which is case-insensitive for ASCII characters.
116116
Repo.with_adapter(fn
117117
:postgres -> where(query, [error], ilike(field(error, ^field), ^"%#{value}%"))
118+
:mysql -> where(query, [error], like(field(error, ^field), ^"%#{value}%"))
118119
:sqlite -> where(query, [error], like(field(error, ^field), ^"%#{value}%"))
119120
end)
120121
end

mix.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ defmodule ErrorTracker.MixProject do
9191
{:phoenix_ecto, "~> 4.6"},
9292
{:plug, "~> 1.10"},
9393
{:postgrex, ">= 0.0.0", optional: true},
94+
{:myxql, ">= 0.0.0", optional: true},
9495
{:ecto_sqlite3, ">= 0.0.0", optional: true},
9596
# Dev dependencies
9697
{:bun, "~> 1.3", only: :dev},

mix.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
2323
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
2424
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
25+
"myxql": {:hex, :myxql, "0.6.4", "1502ea37ee23c31b79725b95d4cc3553693c2bda7421b1febc50722fd988c918", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a3307f4671f3009d3708283649adf205bfe280f7e036fc8ef7f16dbf821ab8e9"},
2526
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
2627
"phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"},
2728
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},

test/support/mysql_repo.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
defmodule ErrorTracker.Test.MySQLRepo do
2+
@moduledoc false
3+
use Ecto.Repo, otp_app: :error_tracker, adapter: Ecto.Adapters.MyXQL
4+
end

test/test_helper.exs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
# Use the appropriate repo for the desired database
22
repo =
33
case System.get_env("DB") do
4-
"sqlite" -> ErrorTracker.Test.LiteRepo
5-
"postgres" -> ErrorTracker.Test.Repo
6-
_other -> raise "Please run either `DB=sqlite mix test` or `DB=postgres mix test`"
4+
"sqlite" ->
5+
ErrorTracker.Test.LiteRepo
6+
7+
"mysql" ->
8+
ErrorTracker.Test.MySQLRepo
9+
10+
"postgres" ->
11+
ErrorTracker.Test.Repo
12+
13+
_other ->
14+
raise "Please run either `DB=sqlite mix test`, `DB=postgres mix test` or `DB=mysql mix test`"
715
end
816

917
Application.put_env(:error_tracker, :repo, repo)

0 commit comments

Comments
 (0)