# 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
```