Skip to content

fix: partial config update#3303

Open
Ziinc wants to merge 3 commits intomainfrom
fix/partial-config-update
Open

fix: partial config update#3303
Ziinc wants to merge 3 commits intomainfrom
fix/partial-config-update

Conversation

@Ziinc
Copy link
Contributor

@Ziinc Ziinc commented Mar 23, 2026

Allows partial updating of a backend config. To accomodate PATCH on nested config values.

Part of O11Y-1578

@Ziinc Ziinc requested review from a team and amokan March 23, 2026 15:54
Copy link
Contributor

@jonatanklosko jonatanklosko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! I dropped one suggestion inline :)

Comment on lines +65 to +70
params = Utils.stringify_keys(params)
existing_config = Utils.stringify_keys(existing_config)

Map.merge(existing_config, params)
|> mod.cast_config()
|> mod.validate_config()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For completeness, you could avoid the stringification and merging here. Currently you have:

@impl Logflare.Backends.Adaptor
def cast_config(params) do
{%{}, %{url: :string, headers: :map, http: :string, gzip: :boolean}}
|> Ecto.Changeset.cast(params, [:url, :headers, :http, :gzip])
|> Logflare.Utils.default_field_value(:http, "http2")
|> Logflare.Utils.default_field_value(:gzip, true)
end

You could change those to accept the existing value and use that instead of the hardcoded %{}:

@impl Logflare.Backends.Adaptor
def cast_config(existing_config, params) do
  {existing_config, %{url: :string, headers: :map, http: :string, gzip: :boolean}}
  |> Ecto.Changeset.cast(params, [:url, :headers, :http, :gzip])
  |> Logflare.Utils.default_field_value(:http, "http2")
  |> Logflare.Utils.default_field_value(:gzip, true)
end

Then here you would pass both config and params and it should just work. You can always pass %{} as existing params, when creating from scratch. This is similar to usual schema changeset function that accepts the struct and params.

Copy link
Contributor

@amokan amokan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good if making the change that Jonatan suggested 👍

nil ->
changeset

%{valid?: false, errors: errors} = changeset ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit. Rebinding changeset here could make things flaky if there was downstream code that inspected Backend-specific fields (doesn't happen today) and expected this to represent a Backend changeset.

Could avoid that by not capturing the failed changeset doing something like:

%{valid?: false, errors: errors} ->
  Enum.reduce(errors, changeset, fn {key, {msg, opts}}, cs ->
    Changeset.add_error(cs, :"config.#{key}", msg, opts)
end)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants