lib/clickhouse/format/json_compact_each_row.ex

if Code.ensure_loaded?(Jason) do
  defmodule ClickHouse.Format.JSONCompactEachRow do
    @moduledoc """
    An implementation of the ClickHouse `JSONCompactEachRow` format.
    """

    @behaviour ClickHouse.Format

    import ClickHouse.Utils, only: [intersperse_map: 3]

    @newline ["\n"]

    ################################
    # ClickHouse.Format Callbacks
    ################################

    @impl ClickHouse.Format
    @spec names() :: [binary()]
    def names, do: ["JSONCompactEachRow"]

    @impl ClickHouse.Format
    @spec decode(raw :: iodata()) :: {ClickHouse.Result.columns(), ClickHouse.Result.rows()}
    def decode(raw) do
      rows = do_decode(raw, [])
      {nil, rows}
    end

    @impl ClickHouse.Format
    @spec encode(ClickHouse.data_types(), rows :: list()) :: iodata()
    def encode(_types, rows) do
      intersperse_map(rows, "\n", &Jason.encode!/1)
    end

    ################################
    # Private API
    ################################

    defp do_decode(raw, rows) do
      case :binary.split(raw, @newline) do
        [row, rest] ->
          row = Jason.decode!(row)
          do_decode(rest, [row | rows])

        [""] ->
          Enum.reverse(rows)
      end
    end
  end
end