# `Concord.Query`
[🔗](https://github.com/gsmlg-dev/concord/blob/main/lib/concord/query.ex#L1)

Query language for Concord key-value store.

Provides pattern matching, range queries, and filtering capabilities
for efficient data retrieval.

## Features

- **Pattern Matching**: Find keys by prefix, suffix, contains, or regex
- **Range Queries**: Retrieve keys within a specific range
- **Value Filtering**: Filter results by value predicates
- **Limit & Offset**: Pagination support
- **Sorted Results**: Automatic key sorting

## Examples

    # Find all user keys
    Concord.Query.keys(prefix: "user:")

    # Find keys in range
    Concord.Query.keys(range: {"user:100", "user:200"})

    # Find keys matching pattern
    Concord.Query.keys(pattern: ~r/user:\d+/)

    # Get values with filtering
    Concord.Query.where(prefix: "product:", filter: fn {_k, v} -> v.price > 100 end)

    # Paginated results
    Concord.Query.keys(prefix: "order:", limit: 50, offset: 100)

# `filter_fn`

```elixir
@type filter_fn() :: ({key(), value()} -&gt; boolean())
```

# `key`

```elixir
@type key() :: binary()
```

# `pattern`

```elixir
@type pattern() :: Regex.t()
```

# `query_opts`

```elixir
@type query_opts() :: [
  prefix: binary(),
  suffix: binary(),
  contains: binary(),
  pattern: pattern(),
  range: range(),
  limit: pos_integer(),
  offset: non_neg_integer()
]
```

# `range`

```elixir
@type range() :: {key(), key()}
```

# `value`

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

# `where_opts`

```elixir
@type where_opts() :: [
  filter: filter_fn(),
  limit: pos_integer(),
  offset: non_neg_integer(),
  prefix: binary(),
  suffix: binary(),
  contains: binary(),
  pattern: pattern(),
  range: range()
]
```

# `count`

```elixir
@spec count(query_opts()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Count keys matching the given criteria.

## Examples

    Concord.Query.count(prefix: "user:")
    # => {:ok, 1543}

    Concord.Query.count(range: {"order:2024-01-01", "order:2024-12-31"})
    # => {:ok, 8234}

# `delete_where`

```elixir
@spec delete_where(query_opts()) :: {:ok, non_neg_integer()} | {:error, term()}
```

Delete all keys matching the given criteria.

Returns the number of keys deleted.

## Examples

    # Delete all temporary keys
    Concord.Query.delete_where(prefix: "temp:")
    # => {:ok, 42}

    # Delete old orders
    Concord.Query.delete_where(range: {"order:2020-01-01", "order:2020-12-31"})
    # => {:ok, 1543}

# `keys`

```elixir
@spec keys(query_opts()) :: {:ok, [key()]} | {:error, term()}
```

Query keys matching the given criteria.

## Options

- `:prefix` - Match keys starting with this string
- `:suffix` - Match keys ending with this string
- `:contains` - Match keys containing this string
- `:pattern` - Match keys against a regex pattern
- `:range` - Match keys in range `{start_key, end_key}` (inclusive)
- `:limit` - Maximum number of results to return
- `:offset` - Number of results to skip

## Examples

    # Prefix matching
    Concord.Query.keys(prefix: "user:")
    # => ["user:1", "user:2", "user:123"]

    # Range query
    Concord.Query.keys(range: {"user:100", "user:200"})
    # => ["user:100", "user:150", "user:200"]

    # Regex pattern
    Concord.Query.keys(pattern: ~r/user:\d{3}/)
    # => ["user:100", "user:200", "user:999"]

    # Pagination
    Concord.Query.keys(prefix: "order:", limit: 50, offset: 100)
    # => 50 keys starting from the 101st key

# `where`

```elixir
@spec where(where_opts()) :: {:ok, [{key(), value()}]} | {:error, term()}
```

Query key-value pairs matching the given criteria.

Similar to `keys/1` but returns both keys and values.

## Options

Same as `keys/1`, plus:

- `:filter` - A function `({key, value} -> boolean())` to filter results by value

## Examples

    # Get all user records
    Concord.Query.where(prefix: "user:")
    # => {:ok, [{"user:1", %{name: "Alice"}}, {"user:2", %{name: "Bob"}}]}

    # Filter by value
    Concord.Query.where(
      prefix: "product:",
      filter: fn {_k, v} -> v.price > 100 end
    )
    # => {:ok, [{"product:1", %{price: 150}}, {"product:2", %{price: 200}}]}

    # Range with filtering
    Concord.Query.where(
      range: {"order:2024-01-01", "order:2024-12-31"},
      filter: fn {_k, v} -> v.status == :completed end
    )

