mirror of
https://github.com/zoldar/jenot.git
synced 2026-01-03 14:32:54 +00:00
Add persistence of reminders and some rudimentary tests
This commit is contained in:
parent
e586e10345
commit
e388cf5af5
11 changed files with 327 additions and 44 deletions
|
|
@ -1,5 +1,9 @@
|
||||||
import Config
|
import Config
|
||||||
|
|
||||||
config :jenot, Jenot.Repo, database: :memory
|
config :jenot, Jenot.Repo,
|
||||||
|
database: "priv/db_test.sqlite",
|
||||||
|
pool: Ecto.Adapters.SQL.Sandbox
|
||||||
|
|
||||||
|
config :logger, :default_handler, level: :warning
|
||||||
|
|
||||||
config :bcrypt_elixir, :log_rounds, 4
|
config :bcrypt_elixir, :log_rounds, 4
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ defmodule Jenot.Note do
|
||||||
field(:deleted_at, :utc_datetime_usec)
|
field(:deleted_at, :utc_datetime_usec)
|
||||||
|
|
||||||
belongs_to(:account, Jenot.Account, type: :binary_id)
|
belongs_to(:account, Jenot.Account, type: :binary_id)
|
||||||
|
has_one(:reminder, Jenot.Reminder)
|
||||||
|
|
||||||
field(:server_updated_at, :utc_datetime_usec)
|
field(:server_updated_at, :utc_datetime_usec)
|
||||||
timestamps(type: :utc_datetime_usec)
|
timestamps(type: :utc_datetime_usec)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ defmodule Jenot.Notes do
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
alias Jenot.Note
|
alias Jenot.Note
|
||||||
|
alias Jenot.Reminder
|
||||||
alias Jenot.Repo
|
alias Jenot.Repo
|
||||||
|
|
||||||
def serialize(note) do
|
def serialize(note) do
|
||||||
|
|
@ -13,6 +14,7 @@ defmodule Jenot.Notes do
|
||||||
|> where(account_id: ^account.id)
|
|> where(account_id: ^account.id)
|
||||||
|> select([n], max(n.server_updated_at))
|
|> select([n], max(n.server_updated_at))
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|
|> Repo.preload(:reminder)
|
||||||
end
|
end
|
||||||
|
|
||||||
def all(account, since \\ nil, include_deleted? \\ false) do
|
def all(account, since \\ nil, include_deleted? \\ false) do
|
||||||
|
|
@ -21,15 +23,20 @@ defmodule Jenot.Notes do
|
||||||
|> maybe_include_deleted(include_deleted?)
|
|> maybe_include_deleted(include_deleted?)
|
||||||
|> maybe_filter_since(since)
|
|> maybe_filter_since(since)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|
|> Repo.preload(:reminder)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add(account, params) do
|
def add(account, params) do
|
||||||
params = deserialize_params(params)
|
params = deserialize_params(params)
|
||||||
changeset = Note.new(account, params)
|
note_changeset = Note.new(account, params)
|
||||||
|
|
||||||
case upsert(changeset, target: [:account_id, :internal_id]) do
|
with {:ok, note} <- upsert_note(note_changeset, target: [:account_id, :internal_id]),
|
||||||
{:ok, note} -> {:ok, note}
|
reminder_changeset = Reminder.update(note, params["reminder"]),
|
||||||
{:error, _changeset} -> {:error, :invalid_data}
|
{:ok, reminder} <- upsert_reminder(reminder_changeset) do
|
||||||
|
{:ok, %{note | reminder: reminder}}
|
||||||
|
else
|
||||||
|
{:error, _} ->
|
||||||
|
{:error, :invalid_data}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -39,6 +46,7 @@ defmodule Jenot.Notes do
|
||||||
|> where(account_id: ^account.id)
|
|> where(account_id: ^account.id)
|
||||||
|> where(internal_id: ^internal_id)
|
|> where(internal_id: ^internal_id)
|
||||||
|> Repo.one()
|
|> Repo.one()
|
||||||
|
|> Repo.preload(:reminder)
|
||||||
|
|
||||||
if note do
|
if note do
|
||||||
{:ok, note}
|
{:ok, note}
|
||||||
|
|
@ -51,11 +59,14 @@ defmodule Jenot.Notes do
|
||||||
params = deserialize_params(params)
|
params = deserialize_params(params)
|
||||||
|
|
||||||
with {:ok, note} <- note_by_internal_id(account, internal_id) do
|
with {:ok, note} <- note_by_internal_id(account, internal_id) do
|
||||||
changeset = Note.update(note, params)
|
note_changeset = Note.update(note, params)
|
||||||
|
|
||||||
case upsert(changeset, target: [:id]) do
|
with {:ok, note} <- upsert_note(note_changeset, target: [:id]),
|
||||||
{:ok, note} -> {:ok, note}
|
reminder_changeset = Reminder.update(note, params["reminder"]),
|
||||||
{:error, _changeset} -> {:error, :invalid_data}
|
{:ok, reminder} <- upsert_reminder(reminder_changeset) do
|
||||||
|
{:ok, %{note | reminder: reminder}}
|
||||||
|
else
|
||||||
|
{:error, _} -> {:error, :invalid_data}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -70,55 +81,83 @@ defmodule Jenot.Notes do
|
||||||
|
|
||||||
defp deserialize_params(params) do
|
defp deserialize_params(params) do
|
||||||
params =
|
params =
|
||||||
case Map.get(params, "content", Map.get(params, :content)) do
|
case Map.get(params, "content") do
|
||||||
data when is_list(data) -> Map.put(params, "content", Jason.encode!(data))
|
data when is_list(data) -> Map.put(params, "content", Jason.encode!(data))
|
||||||
_ -> params
|
_ -> params
|
||||||
end
|
end
|
||||||
|
|
||||||
case Map.get(params, "id", Map.get(params, :id)) do
|
case Map.get(params, "id") do
|
||||||
nil ->
|
nil ->
|
||||||
params
|
params
|
||||||
|
|
||||||
internal_id ->
|
internal_id ->
|
||||||
params
|
params =
|
||||||
|> Map.delete("id")
|
params
|
||||||
|> Map.delete(:id)
|
|> Map.delete("id")
|
||||||
|> Map.put("internal_id", internal_id)
|
|> Map.put("internal_id", internal_id)
|
||||||
|> deserialize_timestamp(:deleted, :deleted_at)
|
|> deserialize_timestamp("deleted", "deleted_at")
|
||||||
|> deserialize_timestamp(:created, :inserted_at)
|
|> deserialize_timestamp("created", "inserted_at")
|
||||||
|> deserialize_timestamp(:updated, :updated_at)
|
|> deserialize_timestamp("updated", "updated_at")
|
||||||
|
|
||||||
|
if reminder = params["reminder"] do
|
||||||
|
reminder =
|
||||||
|
reminder
|
||||||
|
|> Map.put("inserted_at", params["inserted_at"])
|
||||||
|
|> Map.put("updated_at", params["updated_at"])
|
||||||
|
|
||||||
|
Map.put(params, "reminder", reminder)
|
||||||
|
else
|
||||||
|
params
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp serialize_note(note) do
|
defp serialize_note(note) do
|
||||||
note =
|
note =
|
||||||
note
|
note
|
||||||
|> Map.take([:title, :type, :content, :inserted_at, :updated_at, :deleted_at])
|
|> Map.take([:title, :type, :content, :inserted_at, :updated_at, :deleted_at, :reminder])
|
||||||
|> Map.put(:id, note.internal_id)
|
|> Map.put(:id, note.internal_id)
|
||||||
|> serialize_timestamp(:deleted_at, :deleted)
|
|> serialize_timestamp(:deleted_at, :deleted)
|
||||||
|> serialize_timestamp(:inserted_at, :created)
|
|> serialize_timestamp(:inserted_at, :created)
|
||||||
|> serialize_timestamp(:updated_at, :updated)
|
|> serialize_timestamp(:updated_at, :updated)
|
||||||
|
|
||||||
if note.type == :tasklist and not is_nil(note.content) do
|
note =
|
||||||
%{note | content: Jason.decode!(note.content)}
|
if note.type == :tasklist and not is_nil(note.content) do
|
||||||
|
%{note | content: Jason.decode!(note.content)}
|
||||||
|
else
|
||||||
|
note
|
||||||
|
end
|
||||||
|
|
||||||
|
if reminder = note.reminder do
|
||||||
|
time =
|
||||||
|
reminder.time
|
||||||
|
|> Time.to_string()
|
||||||
|
|> String.split(":")
|
||||||
|
|> Enum.take(2)
|
||||||
|
|> Enum.join(":")
|
||||||
|
|
||||||
|
reminder =
|
||||||
|
reminder
|
||||||
|
|> Map.take([:date, :time, :repeat, :unit, :enabled])
|
||||||
|
|> Map.put(:date, Date.to_iso8601(reminder.date))
|
||||||
|
|> Map.put(:time, time)
|
||||||
|
|
||||||
|
%{note | reminder: reminder}
|
||||||
else
|
else
|
||||||
note
|
note
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp deserialize_timestamp(params, src_key, dst_key) do
|
defp deserialize_timestamp(params, src_key, dst_key) do
|
||||||
str_src_key = to_string(src_key)
|
|
||||||
|
|
||||||
value =
|
value =
|
||||||
case Map.get(params, str_src_key, Map.get(params, src_key)) do
|
case Map.get(params, src_key) do
|
||||||
nil -> nil
|
nil -> nil
|
||||||
unix_time -> DateTime.from_unix!(unix_time, :millisecond)
|
unix_time -> DateTime.from_unix!(unix_time, :millisecond)
|
||||||
end
|
end
|
||||||
|
|
||||||
params
|
params
|
||||||
|> Map.delete(src_key)
|
|> Map.delete(src_key)
|
||||||
|> Map.delete(str_src_key)
|
|> Map.put(dst_key, value)
|
||||||
|> Map.put(to_string(dst_key), value)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp serialize_timestamp(data, src_key, dst_key) do
|
defp serialize_timestamp(data, src_key, dst_key) do
|
||||||
|
|
@ -150,7 +189,67 @@ defmodule Jenot.Notes do
|
||||||
where(query, [n], n.server_updated_at > ^datetime)
|
where(query, [n], n.server_updated_at > ^datetime)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp upsert(changeset, opts) do
|
defp upsert_reminder(nil), do: {:ok, nil}
|
||||||
|
|
||||||
|
defp upsert_reminder(changeset) do
|
||||||
|
reminder = Ecto.Changeset.apply_changes(changeset)
|
||||||
|
|
||||||
|
conflict_query =
|
||||||
|
from(r in Reminder,
|
||||||
|
update: [
|
||||||
|
set: [
|
||||||
|
date:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? > ? THEN ? ELSE ? END",
|
||||||
|
^reminder.updated_at,
|
||||||
|
r.updated_at,
|
||||||
|
^reminder.date,
|
||||||
|
r.date
|
||||||
|
),
|
||||||
|
time:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? > ? THEN ? ELSE ? END",
|
||||||
|
^reminder.updated_at,
|
||||||
|
r.updated_at,
|
||||||
|
^reminder.time,
|
||||||
|
r.time
|
||||||
|
),
|
||||||
|
repeat:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? > ? THEN ? ELSE ? END",
|
||||||
|
^reminder.updated_at,
|
||||||
|
r.updated_at,
|
||||||
|
^reminder.repeat,
|
||||||
|
r.repeat
|
||||||
|
),
|
||||||
|
unit:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? > ? THEN ? ELSE ? END",
|
||||||
|
^reminder.updated_at,
|
||||||
|
r.updated_at,
|
||||||
|
^reminder.unit,
|
||||||
|
r.unit
|
||||||
|
),
|
||||||
|
enabled:
|
||||||
|
fragment(
|
||||||
|
"CASE WHEN ? > ? THEN ? ELSE ? END",
|
||||||
|
^reminder.updated_at,
|
||||||
|
r.updated_at,
|
||||||
|
type(^reminder.enabled, :boolean),
|
||||||
|
type(r.enabled, :boolean)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
Repo.insert(changeset,
|
||||||
|
on_conflict: conflict_query,
|
||||||
|
conflict_target: [:note_id],
|
||||||
|
returning: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp upsert_note(changeset, opts) do
|
||||||
conflict_target = Keyword.fetch!(opts, :target)
|
conflict_target = Keyword.fetch!(opts, :target)
|
||||||
type = Ecto.Changeset.get_field(changeset, :type) || :note
|
type = Ecto.Changeset.get_field(changeset, :type) || :note
|
||||||
title = Ecto.Changeset.get_field(changeset, :title) || ""
|
title = Ecto.Changeset.get_field(changeset, :title) || ""
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,35 @@
|
||||||
defmodule Jenot.Reminder do
|
defmodule Jenot.Reminder do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
@primary_key false
|
@primary_key false
|
||||||
schema "reminders" do
|
schema "reminders" do
|
||||||
field(:date, :date)
|
field(:date, :date)
|
||||||
field(:time, :time)
|
field(:time, :time)
|
||||||
field(:repeat, Ecto.Enum, values: [:day, :week, :month, :year])
|
field(:repeat, :integer)
|
||||||
field(:unit, :integer)
|
field(:unit, Ecto.Enum, values: [:day, :week, :month, :year])
|
||||||
field(:enabled, :boolean)
|
field(:enabled, :boolean)
|
||||||
|
|
||||||
belongs_to(:note, Jenot.Note)
|
belongs_to(:note, Jenot.Note, type: :binary_id)
|
||||||
|
|
||||||
timestamps(type: :utc_datetime_usec)
|
timestamps(type: :utc_datetime_usec)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update(_note, nil), do: nil
|
||||||
|
|
||||||
|
def update(note, params) do
|
||||||
|
%__MODULE__{}
|
||||||
|
|> cast(params, [
|
||||||
|
:date,
|
||||||
|
:time,
|
||||||
|
:repeat,
|
||||||
|
:unit,
|
||||||
|
:enabled,
|
||||||
|
:inserted_at,
|
||||||
|
:updated_at
|
||||||
|
])
|
||||||
|
|> validate_required([:date, :time, :enabled, :inserted_at, :updated_at])
|
||||||
|
|> put_assoc(:note, note)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
15
mix.exs
15
mix.exs
|
|
@ -6,7 +6,9 @@ defmodule Jenot.MixProject do
|
||||||
app: :jenot,
|
app: :jenot,
|
||||||
version: "0.1.0",
|
version: "0.1.0",
|
||||||
elixir: "~> 1.17",
|
elixir: "~> 1.17",
|
||||||
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
start_permanent: Mix.env() == :prod,
|
start_permanent: Mix.env() == :prod,
|
||||||
|
aliases: aliases(),
|
||||||
deps: deps(),
|
deps: deps(),
|
||||||
releases: releases()
|
releases: releases()
|
||||||
]
|
]
|
||||||
|
|
@ -19,6 +21,11 @@ defmodule Jenot.MixProject do
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp elixirc_paths(env) when env in [:test, :dev],
|
||||||
|
do: ["lib", "test/support"]
|
||||||
|
|
||||||
|
defp elixirc_paths(_), do: ["lib"]
|
||||||
|
|
||||||
def releases do
|
def releases do
|
||||||
[
|
[
|
||||||
jenot: [
|
jenot: [
|
||||||
|
|
@ -44,4 +51,12 @@ defmodule Jenot.MixProject do
|
||||||
{:plug_live_reload, "~> 0.1.0", only: :dev}
|
{:plug_live_reload, "~> 0.1.0", only: :dev}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp aliases do
|
||||||
|
[
|
||||||
|
setup: ["deps.get", "ecto.create", "ecto.migrate"],
|
||||||
|
"ecto.reset": ["ecto.drop", "ecto.create", "ecto.migrate"],
|
||||||
|
test: ["ecto.create --quiet", "ecto.migrate", "test"]
|
||||||
|
]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,23 @@
|
||||||
defmodule Jenot.Repo.Migrations.UpdateRemindersSchema do
|
defmodule Jenot.Repo.Migrations.UpdateRemindersSchema do
|
||||||
use Ecto.Migration
|
use Ecto.Migration
|
||||||
|
|
||||||
def change do
|
def up do
|
||||||
drop table(:reminders)
|
drop_if_exists table(:reminders)
|
||||||
|
|
||||||
create table(:reminders, primary_key: false) do
|
create table(:reminders, primary_key: false) do
|
||||||
add :date, :date, null: false
|
add :date, :date, null: false
|
||||||
add :time, :time, null: false
|
add :time, :time, null: false
|
||||||
add :repeat_period, :text, null: false
|
add :repeat, :integer, null: true
|
||||||
add :repeat_count, :integer, null: false
|
add :unit, :text, null: true
|
||||||
add :enabled, :boolean, null: false
|
add :enabled, :boolean, null: false
|
||||||
|
|
||||||
add :note_id, references(:note, on_delete: :delete_all), null: false, primary_key: true
|
add :note_id, references(:notes, on_delete: :delete_all, type: :binary_id), primary_key: true
|
||||||
|
|
||||||
timestamps(type: :datetime_usec)
|
timestamps(type: :datetime_usec)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
drop_if_exists table(:reminders)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ export class SyncedNoteStore extends EventTarget {
|
||||||
date: note.reminder.date,
|
date: note.reminder.date,
|
||||||
time: note.reminder.time,
|
time: note.reminder.time,
|
||||||
repeat: note.reminder.count,
|
repeat: note.reminder.count,
|
||||||
unit: note.reminder.unit,
|
unit: note.reminder.unit != "" ? note.reminder.unit : null,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
created: now,
|
created: now,
|
||||||
|
|
|
||||||
124
test/jenot/notes_test.exs
Normal file
124
test/jenot/notes_test.exs
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
defmodule Jenot.NotesTest do
|
||||||
|
use Jenot.DataCase
|
||||||
|
|
||||||
|
alias Jenot.Notes
|
||||||
|
|
||||||
|
setup do
|
||||||
|
Jenot.Accounts.new()
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "add/2" do
|
||||||
|
test "adds a new note", %{account: account} do
|
||||||
|
now = DateTime.utc_now(:millisecond)
|
||||||
|
timestamp = DateTime.to_unix(now, :millisecond)
|
||||||
|
|
||||||
|
assert {:ok, note} =
|
||||||
|
Notes.add(account, %{
|
||||||
|
"id" => "id_#{timestamp}",
|
||||||
|
"type" => "note",
|
||||||
|
"content" => "Example note body",
|
||||||
|
"reminder" => nil,
|
||||||
|
"created" => timestamp,
|
||||||
|
"updated" => timestamp,
|
||||||
|
"deleted" => nil
|
||||||
|
})
|
||||||
|
|
||||||
|
assert is_binary(note.id)
|
||||||
|
assert note.internal_id == "id_#{timestamp}"
|
||||||
|
assert DateTime.compare(now, note.updated_at) == :eq
|
||||||
|
end
|
||||||
|
|
||||||
|
test "adds a new tasklist note", %{account: account} do
|
||||||
|
now = DateTime.utc_now(:millisecond)
|
||||||
|
timestamp = DateTime.to_unix(now, :millisecond)
|
||||||
|
|
||||||
|
assert {:ok, note} =
|
||||||
|
Notes.add(account, %{
|
||||||
|
"id" => "id_#{timestamp}",
|
||||||
|
"type" => "tasklist",
|
||||||
|
"content" => [
|
||||||
|
%{checked: true, content: "First task"},
|
||||||
|
%{checked: false, content: "Second task"}
|
||||||
|
],
|
||||||
|
"reminder" => nil,
|
||||||
|
"created" => timestamp,
|
||||||
|
"updated" => timestamp,
|
||||||
|
"deleted" => nil
|
||||||
|
})
|
||||||
|
|
||||||
|
assert is_binary(note.id)
|
||||||
|
assert note.internal_id == "id_#{timestamp}"
|
||||||
|
|
||||||
|
assert note.content ==
|
||||||
|
Jason.encode!([
|
||||||
|
%{checked: true, content: "First task"},
|
||||||
|
%{checked: false, content: "Second task"}
|
||||||
|
])
|
||||||
|
|
||||||
|
assert DateTime.compare(now, note.updated_at) == :eq
|
||||||
|
end
|
||||||
|
|
||||||
|
test "adds a new note with a reminder", %{account: account} do
|
||||||
|
now = DateTime.utc_now(:millisecond)
|
||||||
|
timestamp = DateTime.to_unix(now, :millisecond)
|
||||||
|
|
||||||
|
assert {:ok, note} =
|
||||||
|
Notes.add(account, %{
|
||||||
|
"id" => "id_#{timestamp}",
|
||||||
|
"type" => "note",
|
||||||
|
"content" => "Example note body",
|
||||||
|
"reminder" => %{
|
||||||
|
"enabled" => true,
|
||||||
|
"date" => "2025-04-01",
|
||||||
|
"time" => "13:00",
|
||||||
|
"repeat" => 1,
|
||||||
|
"unit" => nil
|
||||||
|
},
|
||||||
|
"created" => timestamp,
|
||||||
|
"updated" => timestamp,
|
||||||
|
"deleted" => nil
|
||||||
|
})
|
||||||
|
|
||||||
|
assert note.internal_id == "id_#{timestamp}"
|
||||||
|
assert note.reminder.note_id == note.id
|
||||||
|
assert note.reminder.date == ~D[2025-04-01]
|
||||||
|
assert note.reminder.time == ~T[13:00:00]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "serialize/1" do
|
||||||
|
test "serializes note with a reminder", %{account: account} do
|
||||||
|
now = DateTime.utc_now(:millisecond)
|
||||||
|
timestamp = DateTime.to_unix(now, :millisecond)
|
||||||
|
|
||||||
|
assert {:ok, note} =
|
||||||
|
Notes.add(account, %{
|
||||||
|
"id" => "id_#{timestamp}",
|
||||||
|
"type" => "note",
|
||||||
|
"content" => "Example note body",
|
||||||
|
"reminder" => %{
|
||||||
|
"enabled" => true,
|
||||||
|
"date" => "2025-04-01",
|
||||||
|
"time" => "13:00",
|
||||||
|
"repeat" => 1,
|
||||||
|
"unit" => nil
|
||||||
|
},
|
||||||
|
"created" => timestamp,
|
||||||
|
"updated" => timestamp,
|
||||||
|
"deleted" => nil
|
||||||
|
})
|
||||||
|
|
||||||
|
serialized = Notes.serialize(note)
|
||||||
|
|
||||||
|
assert serialized.id == note.internal_id
|
||||||
|
assert serialized.reminder.date == "2025-04-01"
|
||||||
|
assert serialized.reminder.time == "13:00"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "all/0,1,2" do
|
||||||
|
test "returns no notes for new account", %{account: account} do
|
||||||
|
assert [] = Notes.all(account)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
defmodule JenotTest do
|
|
||||||
use ExUnit.Case
|
|
||||||
doctest Jenot
|
|
||||||
|
|
||||||
test "greets the world" do
|
|
||||||
assert Jenot.hello() == :world
|
|
||||||
end
|
|
||||||
end
|
|
||||||
23
test/support/data_case.ex
Normal file
23
test/support/data_case.ex
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
defmodule Jenot.DataCase do
|
||||||
|
use ExUnit.CaseTemplate
|
||||||
|
|
||||||
|
using do
|
||||||
|
quote do
|
||||||
|
alias Jenot.Repo
|
||||||
|
|
||||||
|
import Ecto
|
||||||
|
import Ecto.Query
|
||||||
|
import Jenot.DataCase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
setup tags do
|
||||||
|
if tags[:async] do
|
||||||
|
raise "SQLite3 does not support async testing in sandbox mode"
|
||||||
|
end
|
||||||
|
|
||||||
|
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Jenot.Repo, shared: true)
|
||||||
|
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
ExUnit.start()
|
ExUnit.start()
|
||||||
|
|
||||||
|
Ecto.Adapters.SQL.Sandbox.mode(Jenot.Repo, :manual)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue