README.md

# Bungee

[![Hex.pm](https://img.shields.io/hexpm/v/bungee.svg)](https://hex.pm/packages/bungee)
[![Hex.pm](https://img.shields.io/hexpm/l/bungee.svg)](https://hex.pm/packages/bungee)
[![Hex.pm](https://img.shields.io/hexpm/dw/bungee.svg)](https://hex.pm/packages/bungee)
[![build status](https://gitlab.com/gt8/open-source/elixir/bungee/badges/master/pipeline.svg)](https://gitlab.com/gt8/open-source/elixir/bungee/commits/master)
[![code coverage](https://gitlab.com/gt8/open-source/elixir/bungee/badges/master/coverage.svg)](https://gitlab.com/gt8/open-source/elixir/bungee/commits/master)

## About

Elasticsearch Client with Repository implementation

## Installation

```elixir
def deps do
  [{:bungee, "~> 1.0.0-alpha1"}]
end
```

## Configuration

Configure the default `:bungee` as such:

```elixir
config :bungee, :config, %{
  uri: "http://elasticsearch:9200", # Required unless Elasticsearch is available on localhost:9200
  index: "index" # Elasticsearch Index to use when repositories don't provide their own
}
```

Using `:bungee` in your test environment? Turn on `:auto_wait_for`:

```elixir
config :bungee, :config, %{
  auto_wait_for: true
}
```

Add `:bungee` to your supervision tree:

```elixir
%{
  id: :bungee,
  start: {Bungee, :start_link, []}
}
```

## Bungee Module

You can have as many modules using the `Bungee` behaviour as you require for all of the types you need to store in Elasticsearch for your application.

```elixir
defmodule MyApp.KeyedType do
  defstruct identifier: nil, forename: nil, surname: nil, emails: []

  def key(type = %__MODULE__{}) do
    type.identifier
  end
end
```

With the corresponding repository:

```elixir
defmodule MyApp.KeyedRepository do
  @moduledoc false
  use Bungee, module: Bungee.Support.KeyedType, type: "simples"
end
```

The `type` option within the repository allows you to configure where your data should be stored in your Elasticsearch index.

**Note:** Type's that provide `key/1` are considered `KeyedTypes`. All this means is that we'll use this function to generate the document identifier when storing with Elasticsearch. `UnkeyedTypes` will received a randomly generated document identifier.

An `unkeyed` type is the same, but with no `key/1` function defined.

```elixir
defmodule MyApp.UnkeyedType do
  defstruct forename: nil, surname: nil, emails: []
end
```

### Available Repository Methods

The following methods are available on your repository modules

### fetch

Fetch a single document by the document identifier

```elixir
MyApp.KeyedRepository.fetch("identifier-123")
```

### save

Save a document to your index, with a status code being returned, this can be either a map or a module

```elixir
{:ok, created_or_updated, projection} = MyApp.KeyedRepository.save(%MyApp.KeyedType{
  identifier: "identifier-123",
  forename: "James",
  surname: "Hetfield"
})
```

If you want to wait for the Elasticsearch index to refresh before returning, you can specify a request option:

```elixir
{:ok, created_or_updated, projection} = MyApp.KeyedRepository.save(%MyApp.KeyedType{
  identifier: "identifier-123",
  forename: "James",
  surname: "Hetfield"
}, refresh: :wait_for)
```

### save!

Similar to `save()` but there will be no status returned

```elixir
new_projection = MyApp.KeyedRepository.save!(%MyApp.KeyedType{
  identifier: "identifier-123",
  forename: "James",
  surname: "Hetfield"
})
```

### delete

Remove an item from the Elasticsearch index

```elixir
MyApp.KeyedRepository.delete("identifier-123")
```

### fetch_by

Used when you want to fetch item(s) by a property on the document, rather than the document identifier

```elixir
MyApp.UnkeyedRepository.fetch_by(:forename, "James")
```

### Running Tests

If you wish to run the tests with Docker, run `make dshell` first; then the below make targets.

```shell
$ make clean deps test
```