diff --git a/README.md b/README.md index 66958d4..3836c56 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Sample operations: * `GSS.Spreadsheet.set_font(pid, %{row_from: nil, row_to: nil, col_from: nil, col_to: nil}, %{font_family: "Source Code Pro"})` * `GSS.Spreadsheet.add_conditional_format(pid, %{row_from: nil, row_to: nil, col_from: nil, col_to: nil}, %{formula: "=$E1=\"TEST\"", color_map: %{red: 1, green: 0.8, blue: 0.8}})` * `GSS.Spreadsheet.update_border(pid, %{row_from: 0, row_to: 10, col_from: 2, col_to: 5}, %{top: %{red: 1, style: "dashed"}, bottom: %{green: 1, blue: 0.7}, left: %{blue: 0.8, alpha: 0.75}})` +* `GSS.Spreadsheet.sort(pid, 100, end_column_index: 5, sort_order: "ASCENDING")` Last function param of `GSS.Spreadsheet` function calls support the same `Keyword` options (in snake_case instead of camelCase), as defined in [Google API Docs](https://developers.google.com/sheets/reference/rest/v4/spreadsheets.values). diff --git a/lib/elixir_google_spreadsheets/spreadsheet.ex b/lib/elixir_google_spreadsheets/spreadsheet.ex index ba969e6..1c919ec 100644 --- a/lib/elixir_google_spreadsheets/spreadsheet.ex +++ b/lib/elixir_google_spreadsheets/spreadsheet.ex @@ -112,6 +112,24 @@ defmodule GSS.Spreadsheet do gen_server_call(pid, :rows, options) end + @doc """ + Sort a worksheet. + + ## Options + + * `:sheet_id` - ID of the sheet to sort (default: 0) + * `:start_row_index` - First row to include in sort (default: 1, to skip header) + * `:end_row_index` - Last row (exclusive) to include (default: row_count + 1) + * `:start_column_index` - First column to include (default: 0) + * `:end_column_index` - Last column (exclusive) to include (required, no default) + * `:dimension_index` - Column to sort by (default: 0) + * `:sort_order` - "ASCENDING" or "DESCENDING" (default: "ASCENDING") + """ + @spec sort(pid, integer, keyword()) :: :ok | {:error, Exception.t()} + def sort(pid, row_count, options \\ []) do + GenServer.call(pid, {:sort, row_count, options}) + end + @spec update_sheet_size(pid, integer(), integer(), Keyword.t()) :: {:ok, list()} | {:error, Exception.t()} def update_sheet_size(pid, row_count, col_count, options \\ []) do @@ -461,6 +479,45 @@ defmodule GSS.Spreadsheet do batch_update_query(spreadsheet_id, request_body, options, state) end + # Sort the spreadsheet + def handle_call({:sort, row_count, options}, _from, %{spreadsheet_id: spreadsheet_id} = state) do + url_suffix = "#{spreadsheet_id}:batchUpdate" + + sheet_id = Keyword.get(options, :sheet_id, 0) + start_row_index = Keyword.get(options, :start_row_index, 1) + end_row_index = Keyword.get(options, :end_row_index, row_count + 1) + start_column_index = Keyword.get(options, :start_column_index, 0) + end_column_index = Keyword.fetch!(options, :end_column_index) + dimension_index = Keyword.get(options, :dimension_index, 0) + sort_order = Keyword.get(options, :sort_order, "ASCENDING") + + request = %{ + sortRange: %{ + range: %{ + sheetId: sheet_id, + startRowIndex: start_row_index, + endRowIndex: end_row_index, + startColumnIndex: start_column_index, + endColumnIndex: end_column_index + }, + sortSpecs: [ + %{ + dimensionIndex: dimension_index, + sortOrder: sort_order + } + ] + } + } + + case spreadsheet_query_post_batch(url_suffix, %{requests: [request]}, []) do + {:json, _response} -> + {:reply, :ok, state} + + {:error, exception} -> + {:reply, {:error, exception}, state} + end + end + # Fetch the given range of cells from the spreadsheet def handle_call({:fetch, the_range}, _from, %{spreadsheet_id: spreadsheet_id} = state) do query = "#{spreadsheet_id}/values/#{maybe_attach_list(state)}#{the_range}" diff --git a/mix.exs b/mix.exs index 2de7899..73d296e 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule GSS.Mixfile do def project do [ app: :elixir_google_spreadsheets, - version: "0.4.0", + version: "0.4.1", elixir: "~> 1.17", description: "Elixir library to read and write data of Google Spreadsheets.", docs: [main: "GSS", extras: ["README.md"]], diff --git a/mix.lock b/mix.lock index a0570b3..9213417 100644 --- a/mix.lock +++ b/mix.lock @@ -1,13 +1,13 @@ %{ "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, "earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, - "ex_doc": {:hex, :ex_doc, "0.37.2", "2a3aa7014094f0e4e286a82aa5194a34dd17057160988b8509b15aa6c292720c", [:mix], [{:earmark_parser, "~> 1.4.42", [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", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "4dfa56075ce4887e4e8b1dcc121cd5fcb0f02b00391fd367ff5336d98fa49049"}, + "ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [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", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"}, "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"}, "gen_stage": {:hex, :gen_stage, "1.2.1", "19d8b5e9a5996d813b8245338a28246307fd8b9c99d1237de199d21efc4c76a1", [:mix], [], "hexpm", "83e8be657fa05b992ffa6ac1e3af6d57aa50aace8f691fcf696ff02f8335b001"}, "goth": {:hex, :goth, "1.4.5", "ee37f96e3519bdecd603f20e7f10c758287088b6d77c0147cd5ee68cf224aade", [:mix], [{:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "0fc2dce5bd710651ed179053d0300ce3a5d36afbdde11e500d57f05f398d5ed5"}, - "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, + "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, "logger_file_backend": {:hex, :logger_file_backend, "0.0.14", "774bb661f1c3fed51b624d2859180c01e386eb1273dc22de4f4a155ef749a602", [:mix], [], "hexpm", "071354a18196468f3904ef09413af20971d55164267427f6257b52cfba03f9e6"},