Packages
umya_spreadsheet_ex
0.7.0
Elixir NIF wrapper for the umya-spreadsheet Rust library, providing Excel (.xlsx) file manipulation capabilities.
Current section
Files
Jump to
Current section
Files
lib/umya_spreadsheet/pivot_table.ex
defmodule UmyaSpreadsheet.PivotTable do
@moduledoc """
Functions for creating and manipulating pivot tables.
Pivot tables allow you to summarize and analyze large datasets quickly.
This module provides functions to:
* Create pivot tables from data ranges
* Configure row, column, and data fields
* Apply formatting to pivot tables
* Refresh pivot table data
"""
alias UmyaSpreadsheet.Spreadsheet
alias UmyaNative
@doc """
Adds a new pivot table to a spreadsheet.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet where the pivot table will be placed
* `name` - Name of the pivot table
* `source_sheet` - Name of the sheet containing the source data
* `source_range` - Range of cells containing the source data in A1 notation (e.g., "A1:D10")
* `target_cell` - Top-left cell for the pivot table placement
* `row_fields` - List of field indices (0-based) to use as row fields
* `column_fields` - List of field indices (0-based) to use as column fields
* `data_fields` - List of data field configs in the format [{field_index, "Function", "Custom Name"}]
where function is one of "sum", "count", "average", "max", "min", "product", "count_nums", "stddev", "stddevp", "var", "varp"
## Examples
```elixir
# Create a simple pivot table from data in sheet "Data"
PivotTable.add_pivot_table(
spreadsheet,
"PivotSheet",
"Sales Analysis",
"Data",
"A1:D100",
"A3",
[0], # Use first column (Region) as row field
[1], # Use second column (Product) as column field
[{2, "sum", "Total Sales"}] # Sum the third column (Sales) as data field
)
```
"""
@spec add_pivot_table(
Spreadsheet.t(),
String.t(),
String.t(),
String.t(),
String.t(),
String.t(),
[integer()],
[integer()],
[{integer(), String.t(), String.t()}]
) :: :ok | {:error, atom()}
def add_pivot_table(
%Spreadsheet{reference: ref},
sheet_name,
name,
source_sheet,
source_range,
target_cell,
row_fields,
column_fields,
data_fields
) do
case UmyaNative.add_pivot_table(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
name,
source_sheet,
source_range,
target_cell,
row_fields,
column_fields,
data_fields
) do
:ok -> :ok
{:ok, :ok} -> :ok
{:error, reason} -> {:error, reason}
end
end
@doc """
Checks if a sheet contains any pivot tables.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet to check
## Examples
```elixir
# Check if a sheet has pivot tables
if PivotTable.has_pivot_tables?(spreadsheet, "Sheet1") do
# Handle sheet with pivot tables
end
```
"""
@spec has_pivot_tables?(Spreadsheet.t(), String.t()) :: boolean()
def has_pivot_tables?(%Spreadsheet{reference: ref}, sheet_name) do
UmyaNative.has_pivot_tables(UmyaSpreadsheet.unwrap_ref(ref), sheet_name)
end
@doc """
Gets the number of pivot tables in a sheet.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet to check
## Examples
```elixir
# Get number of pivot tables
count = PivotTable.count_pivot_tables(spreadsheet, "Sheet1")
```
"""
@spec count_pivot_tables(Spreadsheet.t(), String.t()) :: integer()
def count_pivot_tables(%Spreadsheet{reference: ref}, sheet_name) do
case UmyaNative.count_pivot_tables(UmyaSpreadsheet.unwrap_ref(ref), sheet_name) do
{:ok, count} when is_integer(count) -> count
count when is_integer(count) -> count
_ -> 0
end
end
@doc """
Refreshes all pivot tables in a spreadsheet.
## Parameters
* `spreadsheet` - A spreadsheet struct
## Examples
```elixir
# Refresh all pivot tables
PivotTable.refresh_all_pivot_tables(spreadsheet)
```
"""
@spec refresh_all_pivot_tables(Spreadsheet.t()) :: :ok | {:error, atom()}
def refresh_all_pivot_tables(%Spreadsheet{reference: ref}) do
case UmyaNative.refresh_all_pivot_tables(UmyaSpreadsheet.unwrap_ref(ref)) do
:ok -> :ok
{:ok, :ok} -> :ok
{:error, reason} -> {:error, reason}
end
end
@doc """
Removes a pivot table from a sheet by name.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table to remove
## Examples
```elixir
# Remove a specific pivot table
PivotTable.remove_pivot_table(spreadsheet, "Sheet1", "Sales Analysis")
```
"""
@spec remove_pivot_table(Spreadsheet.t(), String.t(), String.t()) :: :ok | {:error, atom()}
def remove_pivot_table(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
case UmyaNative.remove_pivot_table(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
) do
:ok -> :ok
{:ok, :ok} -> :ok
{:error, reason} -> {:error, reason}
end
end
@doc """
Gets a list of all pivot table names in a sheet.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet to check
## Returns
* `{:ok, [String.t()]}` - List of pivot table names
* `{:error, atom()}` - Error if sheet doesn't exist
## Examples
# Get all pivot table names in a sheet
case PivotTable.get_pivot_table_names(spreadsheet, "Sheet1") do
{:ok, names} -> IO.inspect(names)
{:error, reason} -> IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_names(Spreadsheet.t(), String.t()) ::
{:ok, [String.t()]} | {:error, atom()}
def get_pivot_table_names(%Spreadsheet{reference: ref}, sheet_name) do
UmyaNative.get_pivot_table_names(UmyaSpreadsheet.unwrap_ref(ref), sheet_name)
end
@doc """
Gets detailed information about a specific pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, {name, location, source_range, cache_id}}` - Tuple containing pivot table details
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get detailed info about a pivot table
case PivotTable.get_pivot_table_info(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, {name, location, source_range, cache_id}} ->
IO.puts("Name: " <> name <> ", Location: " <> location)
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_info(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, {String.t(), String.t(), String.t(), String.t()}} | {:error, atom()}
def get_pivot_table_info(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_info(UmyaSpreadsheet.unwrap_ref(ref), sheet_name, pivot_table_name)
end
@doc """
Gets the source data range for a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, {source_sheet, source_range}}` - Tuple containing source sheet name and range
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get source range for a pivot table
case PivotTable.get_pivot_table_source_range(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, {source_sheet, source_range}} ->
IO.puts("Source: " <> source_sheet <> "!" <> source_range)
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_source_range(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, {String.t(), String.t()}} | {:error, atom()}
def get_pivot_table_source_range(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_source_range(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
)
end
@doc """
Gets the target cell (top-left placement) for a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, String.t()}` - Target cell reference (e.g., "A3")
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get target cell for a pivot table
case PivotTable.get_pivot_table_target_cell(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, target_cell} ->
IO.puts("Pivot table starts at: " <> target_cell)
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_target_cell(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, String.t()} | {:error, atom()}
def get_pivot_table_target_cell(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_target_cell(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
)
end
@doc """
Gets the field configuration for a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, {row_fields, column_fields, data_fields}}` - Tuple containing field configurations
* `row_fields` - List of field indices used as row fields
* `column_fields` - List of field indices used as column fields
* `data_fields` - List of data field configs in format [{field_index, function, custom_name}]
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get field configuration for a pivot table
case PivotTable.get_pivot_table_fields(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, {row_fields, column_fields, data_fields}} ->
IO.puts("Row fields: " <> inspect(row_fields))
IO.puts("Column fields: " <> inspect(column_fields))
IO.puts("Data fields: " <> inspect(data_fields))
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_fields(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, {[integer()], [integer()], [{integer(), String.t(), String.t()}]}}
| {:error, atom()}
def get_pivot_table_fields(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_fields(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
)
end
@doc """
Gets all cache fields from a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, fields}` - List of cache fields with their details
* Each field is a tuple: {name, format_id, has_shared_items}
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get all cache fields for a pivot table
case PivotTable.get_pivot_table_cache_fields(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, fields} ->
fields |> Enum.each(fn {name, _, has_items} ->
IO.puts("Field: " <> name <> (if has_items, do: " (has items)", else: ""))
end)
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_cache_fields(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, list({String.t(), non_neg_integer(), boolean()})} | {:error, atom()}
def get_pivot_table_cache_fields(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_cache_fields(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
)
end
@doc """
Gets detailed information about a specific cache field in a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
* `field_index` - Index of the field to get (0-based)
## Returns
* `{:ok, {name, format_id, shared_items}}` - Details for the requested field
* `name` - Field name
* `format_id` - Number format ID for the field
* `shared_items` - List of unique values in this field
* `{:error, atom()}` - Error if sheet, pivot table, or field doesn't exist
## Examples
# Get details for the first cache field
case PivotTable.get_pivot_table_cache_field(spreadsheet, "Sheet1", "Sales Analysis", 0) do
{:ok, {name, _, items}} ->
IO.puts("Field: " <> name)
IO.puts("Unique values: " <> inspect(items))
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_cache_field(Spreadsheet.t(), String.t(), String.t(), non_neg_integer()) ::
{:ok, {String.t(), non_neg_integer(), list(String.t())}} | {:error, atom()}
def get_pivot_table_cache_field(
%Spreadsheet{reference: ref},
sheet_name,
pivot_table_name,
field_index
) do
UmyaNative.get_pivot_table_cache_field(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name,
field_index
)
end
@doc """
Gets all data fields from a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, fields}` - List of data fields with their details
* Each field is a tuple: {name, field_id, base_field_id, base_item}
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get all data fields for a pivot table
case PivotTable.get_pivot_table_data_fields(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, fields} ->
fields |> Enum.each(fn {name, field_id, _, _} ->
IO.puts("Data field: " <> name <> " (field: " <> to_string(field_id) <> ")")
end)
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_data_fields(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, list({String.t(), non_neg_integer(), integer(), non_neg_integer()})}
| {:error, atom()}
def get_pivot_table_data_fields(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_data_fields(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
)
end
@doc """
Gets the cache source configuration for a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
## Returns
* `{:ok, {source_type, worksheet_source}}` - Cache source details
* `source_type` - String describing the source type (worksheet, external, etc.)
* `worksheet_source` - Optional tuple of {sheet_name, range} or nil if not a worksheet source
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Get the cache source for a pivot table
case PivotTable.get_pivot_table_cache_source(spreadsheet, "Sheet1", "Sales Analysis") do
{:ok, {"worksheet", {sheet, range}}} ->
IO.puts("Source data: " <> sheet <> "!" <> range)
{:ok, {source_type, _}} ->
IO.puts("Non-worksheet source: " <> source_type)
{:error, reason} ->
IO.puts("Error: " <> inspect(reason))
end
"""
@spec get_pivot_table_cache_source(Spreadsheet.t(), String.t(), String.t()) ::
{:ok, {String.t(), {String.t(), String.t()} | nil}} | {:error, atom()}
def get_pivot_table_cache_source(%Spreadsheet{reference: ref}, sheet_name, pivot_table_name) do
UmyaNative.get_pivot_table_cache_source(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name
)
end
@doc """
Adds a new data field to an existing pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
* `field_name` - Name for the new data field
* `field_id` - Index of the source field (0-based)
* `base_field_id` - Optional base field ID for calculated fields
* `base_item` - Optional base item for calculated fields
## Returns
* `:ok` - Field was added successfully
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Add a new data field for "Sum of Sales"
:ok = PivotTable.add_pivot_table_data_field(
spreadsheet,
"PivotSheet",
"Sales Analysis",
"Sum of Sales",
2, # Field index 2 (Sales column)
nil,
nil
)
"""
@spec add_pivot_table_data_field(
Spreadsheet.t(),
String.t(),
String.t(),
String.t(),
non_neg_integer(),
integer() | nil,
non_neg_integer() | nil
) :: :ok | {:error, atom()}
def add_pivot_table_data_field(
%Spreadsheet{reference: ref},
sheet_name,
pivot_table_name,
field_name,
field_id,
base_field_id \\ nil,
base_item \\ nil
) do
case UmyaNative.add_pivot_table_data_field(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name,
field_name,
field_id,
base_field_id,
base_item
) do
:ok -> :ok
{:ok, :ok} -> :ok
{:error, reason} -> {:error, reason}
end
end
@doc """
Updates the cache source configuration for a pivot table.
## Parameters
* `spreadsheet` - A spreadsheet struct
* `sheet_name` - Name of the sheet containing the pivot table
* `pivot_table_name` - Name of the pivot table
* `source_sheet` - Name of the sheet containing the source data
* `source_range` - Range of cells containing the source data (e.g., "A1:D10")
## Returns
* `:ok` - Cache was updated successfully
* `{:error, atom()}` - Error if sheet or pivot table doesn't exist
## Examples
# Update the source range for a pivot table
:ok = PivotTable.update_pivot_table_cache(
spreadsheet,
"PivotSheet",
"Sales Analysis",
"DataSheet",
"A1:D20" # Extended range
)
"""
@spec update_pivot_table_cache(
Spreadsheet.t(),
String.t(),
String.t(),
String.t(),
String.t()
) :: :ok | {:error, atom()}
def update_pivot_table_cache(
%Spreadsheet{reference: ref},
sheet_name,
pivot_table_name,
source_sheet,
source_range
) do
case UmyaNative.update_pivot_table_cache(
UmyaSpreadsheet.unwrap_ref(ref),
sheet_name,
pivot_table_name,
source_sheet,
source_range
) do
:ok -> :ok
{:ok, :ok} -> :ok
{:error, reason} -> {:error, reason}
end
end
end