style: fix pre-existing formatting drift across codebase

This commit is contained in:
2026-05-30 09:00:29 +02:00
parent 7045b10738
commit 2bed225133
44 changed files with 452 additions and 194 deletions

View File

@@ -27,7 +27,9 @@ defmodule BDS.AI.ChatConversation do
def changeset(conversation, attrs) do
conversation
|> cast(attrs, [:id, :title, :model, :copilot_session_id, :surface_state, :created_at, :updated_at],
|> cast(
attrs,
[:id, :title, :model, :copilot_session_id, :surface_state, :created_at, :updated_at],
empty_values: [nil]
)
|> validate_required([:id, :title, :created_at, :updated_at])

View File

@@ -263,8 +263,13 @@ defmodule BDS.Desktop.Overlay do
def set_ai_suggestions_error(overlay, _error_message), do: overlay
defp normalize_ai_fields(fields) do
Enum.map(fields, fn %{key: key, label: label, current_value: current,
suggested_value: suggested, locked: locked} = field ->
Enum.map(fields, fn %{
key: key,
label: label,
current_value: current,
suggested_value: suggested,
locked: locked
} = field ->
%{
key: to_string(key),
label: label,

View File

@@ -103,7 +103,9 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
socket
) do
next_data = Map.put(socket.assigns.surface_data, surface_id, fields)
{:noreply, assign(socket, :surface_data, next_data) |> schedule_surface_state_persist() |> build_data()}
{:noreply,
assign(socket, :surface_data, next_data) |> schedule_surface_state_persist() |> build_data()}
end
def handle_event(
@@ -227,8 +229,11 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do
build_data(socket)
socket.assigns.offline_mode ->
Notify.output(dgettext("ui", "Chat"),
dgettext("ui", "Automatic AI actions stay gated by airplane mode."), "info")
Notify.output(
dgettext("ui", "Chat"),
dgettext("ui", "Automatic AI actions stay gated by airplane mode."),
"info"
)
build_data(socket)

View File

@@ -35,14 +35,28 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
known_refs = MapSet.new(tasks, & &1.ref)
drain_tasks(
remaining, tasks, known_refs, project_id, post_id, language, translate_targets, parent
remaining,
tasks,
known_refs,
project_id,
post_id,
language,
translate_targets,
parent
)
send(parent, {:add_images_complete, length(paths)})
end
defp drain_tasks(
[], tasks, _known_refs, _project_id, _post_id, _language, _translate_targets, _parent
[],
tasks,
_known_refs,
_project_id,
_post_id,
_language,
_translate_targets,
_parent
) do
Enum.each(tasks, fn task -> Task.await(task, :infinity) end)
end
@@ -65,7 +79,12 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
new_task =
Task.async(fn ->
process_single_image(
next_path, project_id, post_id, language, translate_targets, parent
next_path,
project_id,
post_id,
language,
translate_targets,
parent
)
end)
@@ -81,8 +100,14 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
)
else
drain_tasks(
[next_path | rest], tasks, known_refs,
project_id, post_id, language, translate_targets, parent
[next_path | rest],
tasks,
known_refs,
project_id,
post_id,
language,
translate_targets,
parent
)
end
@@ -93,7 +118,12 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
new_task =
Task.async(fn ->
process_single_image(
next_path, project_id, post_id, language, translate_targets, parent
next_path,
project_id,
post_id,
language,
translate_targets,
parent
)
end)
@@ -109,8 +139,14 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
)
else
drain_tasks(
[next_path | rest], tasks, known_refs,
project_id, post_id, language, translate_targets, parent
[next_path | rest],
tasks,
known_refs,
project_id,
post_id,
language,
translate_targets,
parent
)
end
end
@@ -124,16 +160,22 @@ defmodule BDS.Desktop.ShellLive.GalleryImport do
end
defp process_single_image(
path, project_id, post_id, language, translate_targets, parent
path,
project_id,
post_id,
language,
translate_targets,
parent
) do
with {:ok, media} <- Media.import_media(%{project_id: project_id, source_path: path}),
true <- String.starts_with?(media.mime_type || "", "image/"),
{:ok, result} <- AI.analyze_image(media.id, language: language),
{:ok, _updated} <- Media.update_media(media.id, %{
title: result.title,
alt: result.alt,
caption: result.caption
}),
{:ok, _updated} <-
Media.update_media(media.id, %{
title: result.title,
alt: result.alt,
caption: result.caption
}),
{:ok, _link} <- Media.link_media_to_post(media.id, post_id) do
translate_media_translations(media.id, translate_targets)
title = result.title || media.original_name

View File

@@ -642,7 +642,10 @@ defmodule BDS.Desktop.ShellLive.ImportEditor do
defp maybe_update_tab_meta(socket, name) do
title = name || dgettext("ui", "Untitled Import")
Notify.tab_meta(:import, socket.assigns.definition_id, title,
Notify.tab_meta(
:import,
socket.assigns.definition_id,
title,
dgettext(
"ui",
"Select a WordPress export file (WXR) and an uploads folder to analyze what would be imported."

View File

@@ -126,8 +126,12 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
Notify.dirty(:media, media.id, false)
Notify.tab_meta(:media, media.id, display_title(updated_media),
updated_media.original_name || updated_media.mime_type || "")
Notify.tab_meta(
:media,
media.id,
display_title(updated_media),
updated_media.original_name || updated_media.mime_type || ""
)
{:noreply, socket}
@@ -484,8 +488,12 @@ defmodule BDS.Desktop.ShellLive.MediaEditor do
Notify.dirty(:media, media.id, false)
Notify.tab_meta(:media, media.id, display_title(updated_media),
updated_media.original_name || updated_media.mime_type || "")
Notify.tab_meta(
:media,
media.id,
display_title(updated_media),
updated_media.original_name || updated_media.mime_type || ""
)
notify_output(socket, dgettext("ui", "Media"), dgettext("ui", "Media saved"))
socket

View File

@@ -471,8 +471,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|> assign(:dirty?, false)
|> build_data()
Notify.tab_meta(:post, post.id, record_title(record, refreshed_post),
Atom.to_string(record_status(record)))
Notify.tab_meta(
:post,
post.id,
record_title(record, refreshed_post),
Atom.to_string(record_status(record))
)
Notify.dirty(:post, post.id, false)
Notify.cancel_auto_save(:post, post.id)
@@ -511,8 +515,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|> assign(:dirty?, false)
|> build_data()
Notify.tab_meta(:post, post.id, record_title(record, refreshed_post),
Atom.to_string(record_status(record)))
Notify.tab_meta(
:post,
post.id,
record_title(record, refreshed_post),
Atom.to_string(record_status(record))
)
Notify.dirty(:post, post.id, false)
notify_output(socket, dgettext("ui", "Post"), dgettext("ui", "Post published"))
@@ -546,9 +554,12 @@ defmodule BDS.Desktop.ShellLive.PostEditor do
|> assign(:dirty?, false)
|> build_data()
Notify.tab_meta(:post, post.id,
Notify.tab_meta(
:post,
post.id,
restored_post.title || restored_post.slug || restored_post.id,
Atom.to_string(restored_post.status || :draft))
Atom.to_string(restored_post.status || :draft)
)
Notify.dirty(:post, post.id, false)
socket

View File

@@ -271,10 +271,10 @@ defmodule BDS.Desktop.ShellLive.TagsEditor do
end
end
attr :color, :string, default: nil
attr :presets, :list, required: true
attr :pick_event, :string, required: true
attr :target, :any, required: true
attr(:color, :string, default: nil)
attr(:presets, :list, required: true)
attr(:pick_event, :string, required: true)
attr(:target, :any, required: true)
defp colour_picker(assigns) do
~H"""

View File

@@ -584,7 +584,9 @@ defmodule BDS.Embeddings do
end
defp duplicate_pairs_with_rebuild(project_id, entries, on_progress) do
case Index.duplicate_pairs(project_id, entries, @duplicate_threshold, on_progress: on_progress) do
case Index.duplicate_pairs(project_id, entries, @duplicate_threshold,
on_progress: on_progress
) do
{:ok, pairs} ->
{:ok, pairs}

View File

@@ -155,7 +155,9 @@ defmodule BDS.Embeddings.Backends.Neural do
# Place model params/tensors on the Apple GPU (Metal) when accelerating with
# EMLX so the compiled inference pass actually runs on-device. EXLA manages
# its own device placement, so nothing to do there.
defp maybe_set_default_backend(:emlx), do: Nx.global_default_backend({EMLX.Backend, device: :gpu})
defp maybe_set_default_backend(:emlx),
do: Nx.global_default_backend({EMLX.Backend, device: :gpu})
defp maybe_set_default_backend(:exla), do: :ok
@doc false

View File

@@ -58,7 +58,11 @@ defmodule BDS.Embeddings.Index do
"""
def neighbors(project_id, query_label, query_vector, limit)
when is_binary(project_id) and is_integer(query_label) and is_binary(query_vector) do
GenServer.call(__MODULE__, {:neighbors, project_id, query_label, query_vector, limit}, :infinity)
GenServer.call(
__MODULE__,
{:neighbors, project_id, query_label, query_vector, limit},
:infinity
)
end
@doc """
@@ -167,7 +171,10 @@ defmodule BDS.Embeddings.Index do
defp build_entry(dimensions, entries) do
count = length(entries)
{:ok, index} = HNSWLib.Index.new(@space, dimensions, count, m: @m, ef_construction: @ef_construction)
{:ok, index} =
HNSWLib.Index.new(@space, dimensions, count, m: @m, ef_construction: @ef_construction)
:ok = HNSWLib.Index.set_ef(index, @ef_search)
tensor =

View File

@@ -82,9 +82,7 @@ defmodule BDS.Generation.Pagefind do
# Returns nil when the page is not marked, so unmarked pages are excluded
# from the index entirely (matching Pagefind semantics).
defp body_text(content) do
case Regex.run(~r/<([a-zA-Z0-9]+)[^>]*\bdata-pagefind-body\b[^>]*>/, content,
return: :index
) do
case Regex.run(~r/<([a-zA-Z0-9]+)[^>]*\bdata-pagefind-body\b[^>]*>/, content, return: :index) do
[{open_start, open_len}, {tag_start, tag_len}] ->
tag = binary_part(content, tag_start, tag_len)
region = scoped_region(content, tag, open_start + open_len)
@@ -117,7 +115,10 @@ defmodule BDS.Generation.Pagefind do
end
defp event_kind(rest, pos, tag) do
if String.starts_with?(binary_part(rest, pos, min(2 + byte_size(tag), byte_size(rest) - pos)), "</") do
if String.starts_with?(
binary_part(rest, pos, min(2 + byte_size(tag), byte_size(rest) - pos)),
"</"
) do
:close
else
:open

View File

@@ -240,7 +240,11 @@ defmodule BDS.Media do
|> Repo.insert_or_update!()
end) do
{:ok, updated_translation} ->
log_sidecar_error(write_translation_sidecar(project, media, updated_translation), media.id)
log_sidecar_error(
write_translation_sidecar(project, media, updated_translation),
media.id
)
:ok = Search.sync_media(media.id)
{:ok, updated_translation}

View File

@@ -178,7 +178,9 @@ defmodule BDS.Preview do
case kind do
:media ->
serve_file(safe_join(server.data_dir, Path.join(["media", relative_path])),
server: server, query_params: query_params)
server: server,
query_params: query_params
)
:generated ->
case BDS.Preview.Router.render_route(server.project_id, request_path) do
@@ -187,7 +189,9 @@ defmodule BDS.Preview do
:not_matched ->
serve_file(safe_join(Path.join(server.data_dir, "html"), relative_path),
server: server, query_params: query_params)
server: server,
query_params: query_params
)
end
end
end
@@ -240,7 +244,10 @@ defmodule BDS.Preview do
defp draft_preview_payload(post, query_params) do
requested_language = query_params |> Map.get("lang") |> normalize_requested_language()
effective_slug = post.template_slug || TemplateSelection.resolve_post_template_slug(post.project_id, post.tags, post.categories)
effective_slug =
post.template_slug ||
TemplateSelection.resolve_post_template_slug(post.project_id, post.tags, post.categories)
case draft_preview_translation(post.id, requested_language, post.language) do
%Translation{} = translation ->

View File

@@ -132,6 +132,7 @@ defmodule BDS.Preview.Router do
defp render(project_id, {:home, page_number}, language, main_language, metadata) do
posts = load_published_list_posts(project_id, metadata)
posts = maybe_resolve_language(posts, language, main_language, project_id)
render_list(project_id, posts, page_number, metadata, language, main_language, %{kind: "core"})
end
@@ -193,7 +194,13 @@ defmodule BDS.Preview.Router do
})
end
defp render(project_id, {:day, year, month, day, page_number}, language, main_language, metadata) do
defp render(
project_id,
{:day, year, month, day, page_number},
language,
main_language,
metadata
) do
posts = load_published_posts_by_day(project_id, year, month, day)
posts = maybe_resolve_language(posts, language, main_language, project_id)
@@ -208,7 +215,8 @@ defmodule BDS.Preview.Router do
## Post rendering
defp render_post(project_id, post, language, main_language) do
{effective_record, body} = resolve_post_for_language(project_id, post, language, main_language)
{effective_record, body} =
resolve_post_for_language(project_id, post, language, main_language)
assigns = %{
id: effective_record.id,
@@ -220,7 +228,9 @@ defmodule BDS.Preview.Router do
_post_record: effective_record
}
effective_slug = post.template_slug || TemplateSelection.resolve_post_template_slug(project_id, post.tags, post.categories)
effective_slug =
post.template_slug ||
TemplateSelection.resolve_post_template_slug(project_id, post.tags, post.categories)
case Rendering.render_post_page(project_id, effective_slug, assigns) do
{:ok, rendered} -> {:ok, rendered}
@@ -370,7 +380,8 @@ defmodule BDS.Preview.Router do
defp archive_page_title(%{kind: "date", year: y, month: m, day: d})
when is_integer(y) and is_integer(m) and is_integer(d),
do: "#{y}-#{String.pad_leading(Integer.to_string(m), 2, "0")}-#{String.pad_leading(Integer.to_string(d), 2, "0")}"
do:
"#{y}-#{String.pad_leading(Integer.to_string(m), 2, "0")}-#{String.pad_leading(Integer.to_string(d), 2, "0")}"
defp archive_page_title(%{kind: "date", year: y, month: m})
when is_integer(y) and is_integer(m),
@@ -504,7 +515,8 @@ defmodule BDS.Preview.Router do
if String.downcase(to_string(language)) == String.downcase(to_string(main_language)) do
posts
else
translations = load_translations_for_language(project_id, Enum.map(posts, & &1.id), language)
translations =
load_translations_for_language(project_id, Enum.map(posts, & &1.id), language)
Enum.map(posts, fn post ->
case Map.get(translations, post.id) do

View File

@@ -104,8 +104,9 @@ defmodule BDS.Projects do
end
@spec project_data_dir(Project.t()) :: String.t()
def project_data_dir(%Project{data_path: data_path}) when is_binary(data_path) and data_path != "",
do: data_path
def project_data_dir(%Project{data_path: data_path})
when is_binary(data_path) and data_path != "",
do: data_path
# A project without an explicit data_path resolves to its folder under the
# per-user default content location — never priv/data inside the repo

View File

@@ -43,12 +43,26 @@ defmodule BDS.Rendering.Filters do
_language_prefix,
context
) do
render_markdown(value, canonical_post_paths, canonical_media_paths, language, context, post_id)
render_markdown(
value,
canonical_post_paths,
canonical_media_paths,
language,
context,
post_id
)
end
@spec render_markdown(term(), map() | nil, map() | nil, String.t(), Liquex.Context.t(), term()) ::
String.t()
def render_markdown(value, canonical_post_paths, canonical_media_paths, language, context, post_id \\ nil) do
def render_markdown(
value,
canonical_post_paths,
canonical_media_paths,
language,
context,
post_id \\ nil
) do
value
|> to_string()
|> replace_built_in_macros(language, context, post_id)
@@ -161,7 +175,11 @@ defmodule BDS.Rendering.Filters do
else
{:error, reason, line} ->
require Logger
Logger.warning("Macro template parse failed (#{template_path}): #{reason} at line #{line}")
Logger.warning(
"Macro template parse failed (#{template_path}): #{reason} at line #{line}"
)
""
{:error, message} ->
@@ -365,8 +383,7 @@ defmodule BDS.Rendering.Filters do
"root_classes" => "macro-photo-archive",
"data_attrs" => [],
"months" => months,
"empty_label" =>
BDS.Gettext.lgettext(language, "render", "No photos found")
"empty_label" => BDS.Gettext.lgettext(language, "render", "No photos found")
},
context
)
@@ -391,8 +408,7 @@ defmodule BDS.Rendering.Filters do
"width" => Map.get(params, "width", width),
"height" => Map.get(params, "height", height),
"aria_label" => "Tag cloud",
"empty_label" =>
BDS.Gettext.lgettext(language, "render", "No tags")
"empty_label" => BDS.Gettext.lgettext(language, "render", "No tags")
},
context
)
@@ -456,9 +472,18 @@ defmodule BDS.Rendering.Filters do
defp group_by_media_month(media_records) do
month_names = %{
1 => "January", 2 => "February", 3 => "March", 4 => "April",
5 => "May", 6 => "June", 7 => "July", 8 => "August",
9 => "September", 10 => "October", 11 => "November", 12 => "December"
1 => "January",
2 => "February",
3 => "March",
4 => "April",
5 => "May",
6 => "June",
7 => "July",
8 => "August",
9 => "September",
10 => "October",
11 => "November",
12 => "December"
}
media_records
@@ -555,8 +580,10 @@ defmodule BDS.Rendering.Filters do
_ -> default
end
end
defp normalize_columns(value, _default, min, max) when is_integer(value),
do: value |> max(min) |> min(max)
defp normalize_columns(_value, default, _min, _max), do: default
defp parse_integer(value) when is_binary(value) do
@@ -565,6 +592,7 @@ defmodule BDS.Rendering.Filters do
_ -> nil
end
end
defp parse_integer(value) when is_integer(value), do: value
defp parse_integer(_value), do: nil
@@ -583,6 +611,7 @@ defmodule BDS.Rendering.Filters do
case DateTime.from_iso8601("#{year}-#{pad(month + 1)}-01T00:00:00Z") do
{:ok, dt, _} ->
dt |> DateTime.add(-1, :second) |> DateTime.to_date() |> Map.get(:day)
_ ->
31
end

View File

@@ -349,5 +349,4 @@ defmodule BDS.Rendering.ListArchive do
do: RenderMetadata.calendar_initial_month(post)
defp calendar_initial_month_from_posts([]), do: nil
end

View File

@@ -63,8 +63,12 @@ defmodule BDS.Scripting do
args,
Keyword.put(opts, :timeout, timeout)
) do
{:ok, nil} -> {:ok, ""}
{:ok, value} -> {:ok, to_string(value)}
{:ok, nil} ->
{:ok, ""}
{:ok, value} ->
{:ok, to_string(value)}
{:error, reason} ->
Logger.warning("execute_macro failed for project #{project_id}: #{inspect(reason)}")
{:error, reason}

View File

@@ -111,8 +111,7 @@ defmodule BDS.Scripting.Capabilities do
get_by_status: one_arg(fn status -> posts_by_status(project_id, status) end),
get_by_year_month: zero_or_one_arg(fn _args -> post_counts_by_year_month(project_id) end),
get_dashboard_stats: zero_or_one_arg(fn _args -> post_dashboard_stats(project_id) end),
get_linked_by:
one_arg(fn post_id -> linked_posts_for(project_id, post_id, :incoming) end),
get_linked_by: one_arg(fn post_id -> linked_posts_for(project_id, post_id, :incoming) end),
get_links_to: one_arg(fn post_id -> linked_posts_for(project_id, post_id, :outgoing) end),
get_preview_url:
two_arg(fn post_id, options -> preview_url(project_id, post_id, options) end),
@@ -157,8 +156,7 @@ defmodule BDS.Scripting.Capabilities do
end),
filter: one_arg(fn filters -> filter_media(project_id, filters) end),
import: one_arg(fn attrs -> import_media(project_id, attrs) end),
get_by_year_month:
zero_or_one_arg(fn _args -> media_counts_by_year_month(project_id) end),
get_by_year_month: zero_or_one_arg(fn _args -> media_counts_by_year_month(project_id) end),
get_file_path: one_arg(fn media_id -> media_file_path(project_id, media_id) end),
update: two_arg(fn media_id, attrs -> update_media(project_id, media_id, attrs) end),
delete: one_arg(fn media_id -> delete_media(project_id, media_id) end),
@@ -172,8 +170,7 @@ defmodule BDS.Scripting.Capabilities do
two_arg(fn media_id, language ->
load_media_translation(project_id, media_id, language)
end),
get_translations:
one_arg(fn media_id -> list_media_translations(project_id, media_id) end),
get_translations: one_arg(fn media_id -> list_media_translations(project_id, media_id) end),
get_url: one_arg(fn media_id -> media_url(project_id, media_id) end),
rebuild_from_files: zero_or_one_arg(fn _args -> rebuild_media_from_files(project_id) end),
regenerate_missing_thumbnails:
@@ -201,8 +198,7 @@ defmodule BDS.Scripting.Capabilities do
get: one_arg(fn script_id -> load_script(project_id, script_id) end),
get_all: zero_or_one_arg(fn _args -> list_scripts(project_id) end),
publish: one_arg(fn script_id -> publish_script(project_id, script_id) end),
rebuild_from_files:
zero_or_one_arg(fn _args -> rebuild_scripts_from_files(project_id) end)
rebuild_from_files: zero_or_one_arg(fn _args -> rebuild_scripts_from_files(project_id) end)
}
end
@@ -295,8 +291,7 @@ defmodule BDS.Scripting.Capabilities do
find_similar: two_arg(fn post_id, limit -> find_similar(post_id, limit) end),
compute_similarities:
two_arg(fn post_id, target_ids -> compute_similarities(post_id, target_ids) end),
suggest_tags:
two_arg(fn post_id, exclude_tags -> suggest_tags(post_id, exclude_tags) end),
suggest_tags: two_arg(fn post_id, exclude_tags -> suggest_tags(post_id, exclude_tags) end),
find_duplicates: zero_or_one_arg(fn _args -> find_duplicates(project_id) end),
dismiss_pair: two_arg(fn post_id_a, post_id_b -> dismiss_pair(post_id_a, post_id_b) end),
index_unindexed_posts: zero_or_one_arg(fn _args -> index_unindexed_posts(project_id) end)

View File

@@ -284,14 +284,24 @@ defmodule BDS.Search do
defp maybe_where_year(query, year) do
year_str = to_string(year)
where(query, [p], fragment("strftime('%Y', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^year_str))
where(
query,
[p],
fragment("strftime('%Y', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^year_str)
)
end
defp maybe_where_month(query, nil), do: query
defp maybe_where_month(query, month) do
month_str = String.pad_leading(to_string(month), 2, "0")
where(query, [p], fragment("strftime('%m', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^month_str))
where(
query,
[p],
fragment("strftime('%m', datetime(? / 1000, 'unixepoch')) = ?", p.created_at, ^month_str)
)
end
defp maybe_where_from(query, nil), do: query
@@ -305,7 +315,10 @@ defmodule BDS.Search do
defp maybe_where_tags(query, tags) do
tags_clause =
Enum.reduce(tags, false, fn tag, acc ->
dynamic([p], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.tags, ^tag))
dynamic(
[p],
^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.tags, ^tag)
)
end)
where(query, [p], ^tags_clause)
@@ -316,7 +329,10 @@ defmodule BDS.Search do
defp maybe_where_tags_media(query, tags) do
tags_clause =
Enum.reduce(tags, false, fn tag, acc ->
dynamic([m], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", m.tags, ^tag))
dynamic(
[m],
^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", m.tags, ^tag)
)
end)
where(query, [m], ^tags_clause)
@@ -327,7 +343,15 @@ defmodule BDS.Search do
defp maybe_where_categories(query, categories) do
categories_clause =
Enum.reduce(categories, false, fn category, acc ->
dynamic([p], ^acc or fragment("EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)", p.categories, ^category))
dynamic(
[p],
^acc or
fragment(
"EXISTS (SELECT 1 FROM json_each(?) WHERE value = ?)",
p.categories,
^category
)
)
end)
where(query, [p], ^categories_clause)
@@ -548,8 +572,6 @@ defmodule BDS.Search do
)
end
defp post_index_fields(post, translations) do
post_language = normalize_language(post.language)
@@ -656,8 +678,8 @@ defmodule BDS.Search do
else
Repo.all(
from translation in MediaTranslation,
where: translation.translation_for in ^media_ids,
select: {translation.translation_for, translation}
where: translation.translation_for in ^media_ids,
select: {translation.translation_for, translation}
)
|> Enum.group_by(fn {media_id, _} -> media_id end, fn {_, translation} -> translation end)
end

View File

@@ -239,6 +239,7 @@ defmodule BDS.Tags do
{:error, changeset} -> Repo.rollback(changeset)
end
end)
Enum.map(affected_posts, & &1.id)
end)
|> case do

View File

@@ -79,8 +79,14 @@ defmodule BDS.UI.Dashboard do
from post in Post,
where: post.project_id == ^project_id,
group_by: [
fragment("CAST(strftime('%Y', datetime(? / 1000, 'unixepoch')) AS INTEGER)", post.created_at),
fragment("CAST(strftime('%m', datetime(? / 1000, 'unixepoch')) AS INTEGER)", post.created_at)
fragment(
"CAST(strftime('%Y', datetime(? / 1000, 'unixepoch')) AS INTEGER)",
post.created_at
),
fragment(
"CAST(strftime('%m', datetime(? / 1000, 'unixepoch')) AS INTEGER)",
post.created_at
)
],
select: %{
year: