This is an automated email from the ASF dual-hosted git repository.

fresh-borzoni pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fluss-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new 7848aaa9 [elixir] chore: Add dialyzer and tighten Fluss.Config setter 
guards (#582)
7848aaa9 is described below

commit 7848aaa9d735265416a6eb308b1de618f5d9cacc
Author: Nicoleta Lazar <[email protected]>
AuthorDate: Sun May 31 03:39:51 2026 +0100

    [elixir] chore: Add dialyzer and tighten Fluss.Config setter guards (#582)
---
 .github/workflows/build_and_test_elixir.yml | 12 +++++++++
 bindings/elixir/.gitignore                  |  1 +
 bindings/elixir/lib/fluss/config.ex         | 42 ++++++++++++++++-------------
 bindings/elixir/mix.exs                     | 24 ++++++++++++++++-
 bindings/elixir/mix.lock                    |  2 ++
 bindings/elixir/test/config_test.exs        |  8 ++++++
 6 files changed, 69 insertions(+), 20 deletions(-)

diff --git a/.github/workflows/build_and_test_elixir.yml 
b/.github/workflows/build_and_test_elixir.yml
index 03f3329e..ce5de2df 100644
--- a/.github/workflows/build_and_test_elixir.yml
+++ b/.github/workflows/build_and_test_elixir.yml
@@ -91,6 +91,18 @@ jobs:
         working-directory: bindings/elixir
         run: mix credo
 
+      - name: Cache PLT
+        uses: actions/cache@v4
+        with:
+          path: bindings/elixir/priv/plts/
+          key: ${{ runner.os }}-otp-${{ steps.beam.outputs.otp-version 
}}-elixir-${{ steps.beam.outputs.elixir-version }}-mix-${{ 
hashFiles('bindings/elixir/mix.lock') }}-plt
+          restore-keys: |
+            ${{ runner.os }}-otp-${{ steps.beam.outputs.otp-version 
}}-elixir-${{ steps.beam.outputs.elixir-version }}-mix-
+
+      - name: Dialyzer
+        working-directory: bindings/elixir
+        run: mix dialyzer
+
       - name: Run unit tests
         working-directory: bindings/elixir
         run: mix test
diff --git a/bindings/elixir/.gitignore b/bindings/elixir/.gitignore
index 90277ffb..dd00538b 100644
--- a/bindings/elixir/.gitignore
+++ b/bindings/elixir/.gitignore
@@ -4,6 +4,7 @@ deps/
 
 # Generated NIF shared library
 priv/native/
+priv/plts/
 
 # Crash dumps
 erl_crash.dump
diff --git a/bindings/elixir/lib/fluss/config.ex 
b/bindings/elixir/lib/fluss/config.ex
index 8aaacf79..d7075b9e 100644
--- a/bindings/elixir/lib/fluss/config.ex
+++ b/bindings/elixir/lib/fluss/config.ex
@@ -88,6 +88,8 @@ defmodule Fluss.Config do
           writer_retries: non_neg_integer() | nil
         }
 
+  defguardp is_non_neg_integer(n) when is_integer(n) and n >= 0
+
   @spec new(String.t()) :: t()
   def new(bootstrap_servers) when is_binary(bootstrap_servers) do
     %__MODULE__{bootstrap_servers: bootstrap_servers}
@@ -101,45 +103,46 @@ defmodule Fluss.Config do
     do: %{config | bootstrap_servers: servers}
 
   @spec set_connect_timeout_ms(t(), non_neg_integer()) :: t()
-  def set_connect_timeout_ms(%__MODULE__{} = config, ms) when is_integer(ms),
+  def set_connect_timeout_ms(%__MODULE__{} = config, ms) when 
is_non_neg_integer(ms),
     do: %{config | connect_timeout_ms: ms}
 
   @spec set_remote_file_download_thread_num(t(), non_neg_integer()) :: t()
   def set_remote_file_download_thread_num(%__MODULE__{} = config, threads)
-      when is_integer(threads),
+      when is_non_neg_integer(threads),
       do: %{config | remote_file_download_thread_num: threads}
 
   @spec set_scanner_log_fetch_max_bytes(t(), non_neg_integer()) :: t()
   def set_scanner_log_fetch_max_bytes(%__MODULE__{} = config, max_bytes)
-      when is_integer(max_bytes),
+      when is_non_neg_integer(max_bytes),
       do: %{config | scanner_log_fetch_max_bytes: max_bytes}
 
   @spec set_scanner_log_fetch_max_bytes_for_bucket(t(), non_neg_integer()) :: 
t()
   def set_scanner_log_fetch_max_bytes_for_bucket(%__MODULE__{} = config, 
max_bytes)
-      when is_integer(max_bytes),
+      when is_non_neg_integer(max_bytes),
       do: %{config | scanner_log_fetch_max_bytes_for_bucket: max_bytes}
 
   @spec set_scanner_log_fetch_min_bytes(t(), non_neg_integer()) :: t()
   def set_scanner_log_fetch_min_bytes(%__MODULE__{} = config, min_bytes)
-      when is_integer(min_bytes),
+      when is_non_neg_integer(min_bytes),
       do: %{config | scanner_log_fetch_min_bytes: min_bytes}
 
   @spec set_scanner_log_fetch_wait_max_time_ms(t(), non_neg_integer()) :: t()
   def set_scanner_log_fetch_wait_max_time_ms(%__MODULE__{} = config, wait_ms)
-      when is_integer(wait_ms),
+      when is_non_neg_integer(wait_ms),
       do: %{config | scanner_log_fetch_wait_max_time_ms: wait_ms}
 
   @spec set_scanner_log_max_poll_records(t(), non_neg_integer()) :: t()
-  def set_scanner_log_max_poll_records(%__MODULE__{} = config, num) when 
is_integer(num),
+  def set_scanner_log_max_poll_records(%__MODULE__{} = config, num) when 
is_non_neg_integer(num),
     do: %{config | scanner_log_max_poll_records: num}
 
   @spec set_scanner_remote_log_prefetch_num(t(), non_neg_integer()) :: t()
-  def set_scanner_remote_log_prefetch_num(%__MODULE__{} = config, num) when 
is_integer(num),
-    do: %{config | scanner_remote_log_prefetch_num: num}
+  def set_scanner_remote_log_prefetch_num(%__MODULE__{} = config, num)
+      when is_non_neg_integer(num),
+      do: %{config | scanner_remote_log_prefetch_num: num}
 
   @spec set_scanner_remote_log_read_concurrency(t(), non_neg_integer()) :: t()
   def set_scanner_remote_log_read_concurrency(%__MODULE__{} = config, 
concurrency)
-      when is_integer(concurrency),
+      when is_non_neg_integer(concurrency),
       do: %{config | scanner_remote_log_read_concurrency: concurrency}
 
   @spec set_security_protocol(t(), String.t()) :: t()
@@ -163,11 +166,11 @@ defmodule Fluss.Config do
     do: %{config | writer_acks: acks}
 
   @spec set_writer_batch_size(t(), non_neg_integer()) :: t()
-  def set_writer_batch_size(%__MODULE__{} = config, size) when 
is_integer(size),
+  def set_writer_batch_size(%__MODULE__{} = config, size) when 
is_non_neg_integer(size),
     do: %{config | writer_batch_size: size}
 
   @spec set_writer_batch_timeout_ms(t(), non_neg_integer()) :: t()
-  def set_writer_batch_timeout_ms(%__MODULE__{} = config, ms) when 
is_integer(ms),
+  def set_writer_batch_timeout_ms(%__MODULE__{} = config, ms) when 
is_non_neg_integer(ms),
     do: %{config | writer_batch_timeout_ms: ms}
 
   @spec set_writer_bucket_no_key_assigner(t(), :sticky | :round_robin) :: t()
@@ -176,11 +179,11 @@ defmodule Fluss.Config do
       do: %{config | writer_bucket_no_key_assigner: assigner}
 
   @spec set_writer_buffer_memory_size(t(), non_neg_integer()) :: t()
-  def set_writer_buffer_memory_size(%__MODULE__{} = config, size) when 
is_integer(size),
+  def set_writer_buffer_memory_size(%__MODULE__{} = config, size) when 
is_non_neg_integer(size),
     do: %{config | writer_buffer_memory_size: size}
 
   @spec set_writer_buffer_wait_timeout_ms(t(), non_neg_integer()) :: t()
-  def set_writer_buffer_wait_timeout_ms(%__MODULE__{} = config, ms) when 
is_integer(ms),
+  def set_writer_buffer_wait_timeout_ms(%__MODULE__{} = config, ms) when 
is_non_neg_integer(ms),
     do: %{config | writer_buffer_wait_timeout_ms: ms}
 
   @spec set_writer_dynamic_batch_size_enabled(t(), boolean()) :: t()
@@ -189,8 +192,9 @@ defmodule Fluss.Config do
       do: %{config | writer_dynamic_batch_size_enabled: enabled}
 
   @spec set_writer_dynamic_batch_size_min(t(), non_neg_integer()) :: t()
-  def set_writer_dynamic_batch_size_min(%__MODULE__{} = config, size) when 
is_integer(size),
-    do: %{config | writer_dynamic_batch_size_min: size}
+  def set_writer_dynamic_batch_size_min(%__MODULE__{} = config, size)
+      when is_non_neg_integer(size),
+      do: %{config | writer_dynamic_batch_size_min: size}
 
   @spec set_writer_enable_idempotence(t(), boolean()) :: t()
   def set_writer_enable_idempotence(%__MODULE__{} = config, enabled)
@@ -199,15 +203,15 @@ defmodule Fluss.Config do
 
   @spec set_writer_max_inflight_requests_per_bucket(t(), non_neg_integer()) :: 
t()
   def set_writer_max_inflight_requests_per_bucket(%__MODULE__{} = config, n)
-      when is_integer(n),
+      when is_non_neg_integer(n),
       do: %{config | writer_max_inflight_requests_per_bucket: n}
 
   @spec set_writer_request_max_size(t(), non_neg_integer()) :: t()
-  def set_writer_request_max_size(%__MODULE__{} = config, size) when 
is_integer(size),
+  def set_writer_request_max_size(%__MODULE__{} = config, size) when 
is_non_neg_integer(size),
     do: %{config | writer_request_max_size: size}
 
   @spec set_writer_retries(t(), non_neg_integer()) :: t()
-  def set_writer_retries(%__MODULE__{} = config, n) when is_integer(n),
+  def set_writer_retries(%__MODULE__{} = config, n) when is_non_neg_integer(n),
     do: %{config | writer_retries: n}
 
   @spec get_bootstrap_servers(t()) :: String.t()
diff --git a/bindings/elixir/mix.exs b/bindings/elixir/mix.exs
index f5d416d8..9334be90 100644
--- a/bindings/elixir/mix.exs
+++ b/bindings/elixir/mix.exs
@@ -27,8 +27,14 @@ defmodule Fluss.MixProject do
       elixir: "~> 1.15",
       start_permanent: Mix.env() == :prod,
       elixirc_paths: elixirc_paths(Mix.env()),
+      aliases: aliases(),
       deps: deps(),
       description: "Elixir client for Apache Fluss",
+      dialyzer: [
+        plt_add_apps: [:ex_unit, :mix],
+        plt_file: {:no_warn, "priv/plts/dialyzer.plt"},
+        list_unused_filters: true
+      ],
       package: package()
     ]
   end
@@ -46,7 +52,23 @@ defmodule Fluss.MixProject do
     [
       {:rustler, "~> 0.37"},
       {:ex_doc, "~> 0.31", only: :dev, runtime: false},
-      {:credo, "~> 1.7", only: [:dev, :test], runtime: false}
+      {:credo, "~> 1.7", only: [:dev, :test], runtime: false},
+      {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}
+    ]
+  end
+
+  defp aliases do
+    [
+      check: static_checks()
+    ]
+  end
+
+  defp static_checks do
+    [
+      "format --check-formatted",
+      "credo --strict",
+      "compile --warnings-as-errors",
+      "dialyzer"
     ]
   end
 
diff --git a/bindings/elixir/mix.lock b/bindings/elixir/mix.lock
index b1170d3f..5e931125 100644
--- a/bindings/elixir/mix.lock
+++ b/bindings/elixir/mix.lock
@@ -1,7 +1,9 @@
 %{
   "bunt": {:hex, :bunt, "1.0.0", 
"081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], 
"hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
   "credo": {:hex, :credo, "1.7.17", 
"f92b6aa5b26301eaa5a35e4d48ebf5aa1e7094ac00ae38f87086c562caf8a22f", [:mix], 
[{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, 
{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: 
false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], 
"hexpm", "1eb5645c835f0b6c9b5410f94b5a185057bcf6d62a9c2b476da971cde8749645"},
+  "dialyxir": {:hex, :dialyxir, "1.4.7", 
"dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], 
[{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", 
"b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"},
   "earmark_parser": {:hex, :earmark_parser, "1.4.44", 
"f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], 
"hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
+  "erlex": {:hex, :erlex, "0.2.9", 
"7debbbaa9f4f368b8cd648983e0f1d7963028508e9c59e9d4ed504e94ef52a55", [:mix], [], 
"hexpm", "8cfffc0ec7159e6d73de2ab28a588064de80f88b2798d5cbe4482cbbc200178b"},
   "ex_doc": {:hex, :ex_doc, "0.40.1", 
"67542e4b6dde74811cfd580e2c0149b78010fd13001fda7cfeb2b2c2ffb1344d", [:mix], 
[{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: 
false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: 
true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: 
"hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: 
:makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [ 
[...]
   "file_system": {:hex, :file_system, "1.1.1", 
"31864f4685b0148f25bd3fbef2b1228457c0c89024ad67f7a81a3ffbc0bbad3a", [:mix], [], 
"hexpm", "7a15ff97dfe526aeefb090a7a9d3d03aa907e100e262a0f8f7746b78f8f87a5d"},
   "jason": {:hex, :jason, "1.4.4", 
"b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], 
[{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: 
true]}], "hexpm", 
"c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
diff --git a/bindings/elixir/test/config_test.exs 
b/bindings/elixir/test/config_test.exs
index f4b8a11c..767ac247 100644
--- a/bindings/elixir/test/config_test.exs
+++ b/bindings/elixir/test/config_test.exs
@@ -214,6 +214,14 @@ defmodule Fluss.ConfigTest do
     assert config.writer_retries == 5
   end
 
+  test "set_writer_batch_size/2 rejects negative integers" do
+    config = Fluss.Config.new("h:9123")
+
+    assert_raise FunctionClauseError, fn ->
+      Fluss.Config.set_writer_batch_size(config, -1)
+    end
+  end
+
   test "setters chain correctly" do
     config =
       Fluss.Config.new("localhost:9123")

Reply via email to