# `Yex.Map`
[🔗](https://github.com/satoren/y_ex/blob/main/lib/shared_type/map.ex#L1)

A shareable Map type that supports concurrent modifications with automatic conflict resolution.
This module provides functionality for collaborative key-value pair management with support for
nested shared types and JSON compatibility.

## Features
- Concurrent modifications with automatic conflict resolution
- Support for nested shared types (Array, Text, Map)
- JSON-compatible serialization
- Key-value pair management with atomic operations
- Observable changes for real-time collaboration

# `t`

```elixir
@type t() :: %Yex.Map{doc: Yex.Doc.t(), reference: reference()}
```

# `value`

```elixir
@type value() :: term()
```

# `as_prelim`

```elixir
@spec as_prelim(t()) :: Yex.MapPrelim.t()
```

Converts the map to its preliminary representation.
This is useful when you need to serialize or transfer the map's contents.

## Parameters
  * `map` - The map to convert

# `delete`

```elixir
@spec delete(t(), binary()) :: :ok
```

Deletes a key from the map.
Returns :ok on success, :error on failure.

## Parameters
  * `map` - The map to modify
  * `key` - The key to delete

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> Yex.Map.delete(map, "plane")
    :ok

# `fetch`

```elixir
@spec fetch(t(), binary()) :: {:ok, value()} | :error
```

Retrieves a value by key from the map.
Returns {:ok, value} if found, :error if not found.

## Parameters
  * `map` - The map to query
  * `key` - The key to look up

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> Yex.Map.fetch(map, "plane")
    {:ok, ["Hello", "World"]}
    iex> Yex.Map.fetch(map, "not_found")
    :error

# `fetch!`

```elixir
@spec fetch!(t(), binary()) :: value()
```

Similar to fetch/2 but raises ArgumentError if the key is not found.

## Parameters
  * `map` - The map to query
  * `key` - The key to look up

## Raises
  * ArgumentError - If the key is not found

# `get`

```elixir
@spec get(t(), binary(), default :: value()) :: value()
```

get a key from the map.
  ## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> Yex.Map.get(map, "plane")
    ["Hello", "World"]
    iex> Yex.Map.get(map, "not_found")
    nil

# `get_lazy`

```elixir
@spec get_lazy(t(), binary(), fun :: (-&gt; value())) :: value()
```

Gets a value by key from the map, or lazily evaluates the given function if the key is not found.
This is useful when the default value is expensive to compute and should only be evaluated when needed.

## Parameters
  * `map` - The map to query
  * `key` - The key to look up
  * `fun` - A function that returns the default value (only called if key is not found)

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> Yex.Map.get_lazy(map, "plane", fn -> ["Default"] end)
    ["Hello", "World"]
    iex> Yex.Map.get_lazy(map, "not_found", fn -> ["Computed"] end)
    ["Computed"]

Particularly useful with `set_and_get/3` for get-or-create patterns:

    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> # Get existing value or create and return new one
    iex> value = Yex.Map.get_lazy(map, "counter", fn ->
    ...>   Yex.Map.set_and_get(map, "counter", 0)
    ...> end)
    iex> value
    0.0
    iex> # Next call returns existing value without calling the function
    iex> Yex.Map.get_lazy(map, "counter", fn -> Yex.Map.set_and_get(map, "counter", 0) end)
    0.0

# `has_key?`

```elixir
@spec has_key?(t(), binary()) :: boolean()
```

Checks if a key exists in the map.
Returns true if the key exists, false otherwise.

## Parameters
  * `map` - The map to check
  * `key` - The key to look for

# `keys`

```elixir
@spec keys(t()) :: [binary()]
```

Returns a list of all keys in the map.

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "foo", "bar")
    iex> Yex.Map.set(map, "baz", "qux")
    iex> keys = Yex.Map.keys(map)
    iex> Enum.sort(keys) # keys order is not guaranteed
    ["baz", "foo"]

# `link`

```elixir
@spec link(t(), binary()) :: Yex.WeakPrelim.t() | nil
```

### ⚠️ Experimental
Creates a weak link to a value in the map by key.
Returns [Yex.WeakPrelim] to a given `key`, if it exists in a current map.

# `set`

```elixir
@spec set(t(), binary(), Yex.input_type()) :: :ok
```

Sets a key-value pair in the map.
Returns :ok on success, :error on failure.

## Parameters
  * `map` - The map to modify
  * `key` - The key to set
  * `content` - The value to associate with the key

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    :ok

# `set_and_get`

```elixir
@spec set_and_get(t(), binary(), Yex.input_type()) :: value()
```

Sets a key-value pair in the map and returns the set value.
Returns the value on success, raises on failure.

## Parameters
  * `map` - The map to modify
  * `key` - The key to set
  * `content` - The value to associate with the key

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> value = Yex.Map.set_and_get(map, "plane", ["Hello", "World"])
    iex> value
    ["Hello", "World"]

# `size`

```elixir
@spec size(t()) :: integer()
```

Returns the number of key-value pairs in the map.

# `to_json`

```elixir
@spec to_json(t()) :: map()
```

Converts the map to a JSON-compatible format.
This is useful for serialization or when you need to transfer the map's contents.

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "array", Yex.ArrayPrelim.from(["Hello", "World"]))
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> assert %{"plane" => ["Hello", "World"], "array" => ["Hello", "World"]} = Yex.Map.to_json(map)

# `to_list`

```elixir
@spec to_list(t()) :: [{binary(), term()}]
```

Converts the map to a list of key-value tuples.
## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> Yex.Map.to_list(map)
    [{"plane", ["Hello", "World"]}]

# `to_map`

```elixir
@spec to_map(t()) :: map()
```

Converts the map to a standard Elixir map.
This is useful when you need to work with the map's contents in a non-collaborative context.

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "array", Yex.ArrayPrelim.from(["Hello", "World"]))
    iex> Yex.Map.set(map, "plane", ["Hello", "World"])
    iex> assert %{"plane" => ["Hello", "World"], "array" => %Yex.Array{}} = Yex.Map.to_map(map)

# `values`

```elixir
@spec values(t()) :: [value()]
```

Returns a list of all values in the map.

## Examples
    iex> doc = Yex.Doc.new()
    iex> map = Yex.Doc.get_map(doc, "map")
    iex> Yex.Map.set(map, "foo", "bar")
    iex> Yex.Map.set(map, "baz", 123)
    iex> values = Yex.Map.values(map)
    iex> Enum.sort(values) # values order is not guaranteed
    [123.0, "bar"]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
