Current section

Files

Jump to
fsdb lib server.ex
Raw

lib/server.ex

defmodule Fsdb.Server do
@moduledoc """
Fsdb.Server module.
```elixir
#run with: mix sample_server
path = Path.expand("_build/dev/.fsdb")
{:ok, db} = Fsdb.Server.start_link([path: path])
#drop to start over
:ok = Fsdb.Server.drop(db, "table1")
:ok = Fsdb.Server.create(db, "table1")
#insert generates and returns an autoincrementing id
{:ok, 1} = Fsdb.Server.insert(db, "table1", "row1")
{:ok, "row1"} = Fsdb.Server.fetch(db, "table1", 1)
#operation on nonexisting ids return not found
:nf = Fsdb.Server.delete(db, "table1", 5)
:nf = Fsdb.Server.update(db, "table1", 5, "row5+")
#save overrides and updates id generator
:ok = Fsdb.Server.save(db, "table1", 5, "row5")
:ok = Fsdb.Server.save(db, "table1", 3, "row3")
#continue +1 of largest id used/generated before
{:ok, 6} = Fsdb.Server.insert(db, "table1", "row6")
#operations that get back previous value
{:ok, "row5"} = Fsdb.Server.update(db, "table1", 5, "row5+")
{:ok, "row5+"} = Fsdb.Server.save(db, "table1", 5, "row5++")
{:ok, "row5++"} = Fsdb.Server.delete(db, "table1", 5)
#tuples may not be id ordered
[{1, "row1"}, {3, "row3"}, {6, "row6"}] = Fsdb.Server.list(db, "table1")
```
"""
use GenServer
##########################################
# Public API
##########################################
@doc """
Starts the GenServer.
`params` *must* contain a valid path in the `:path` key.
`opts` is optional and is passed verbatim to GenServer.
Returns `{:ok, pid}`.
## Example
```
Fsdb.Server.start_link([path: ".fsdb"], [name: Fsdb.Server])
```
"""
def start_link(params, opts \\ []) do
GenServer.start_link(__MODULE__, params, opts)
end
@doc """
Stops the GenServer.
Returns `:ok`.
"""
def stop(pid) do
GenServer.stop(pid)
end
@doc """
Creates a table with name `table`.
Returns `:ok`.
"""
def create(pid, table) do
GenServer.call(pid, {:create, table})
end
@doc """
Drops the table named `table`.
Returns `:ok`.
"""
def drop(pid, table) do
GenServer.call(pid, {:drop, table})
end
@doc """
Returns all rows in table `table`.
Returns `[{id, row}, ...]`.
"""
def list(pid, table) do
GenServer.call(pid, {:list, table})
end
@doc """
Inserts row `row` in table `table` with auto generated id.
Returns `{:ok, id}`.
"""
def insert(pid, table, row) do
GenServer.call(pid, {:insert, table, row})
end
@doc """
Inserts or updates row `row` in table `table` with specific id `id`.
If the provided id is greater than the last autogenerated id then
the autogenerated id is updated to the provided one.
Returns `:ok | {:ok, previous_row}`.
"""
def save(pid, table, id, row) when is_integer(id) do
GenServer.call(pid, {:save, table, id, row})
end
@doc """
Fetches the row in table `table` having the id `id`.
Returns `{:ok, row} | :nf`.
"""
def fetch(pid, table, id) do
GenServer.call(pid, {:fetch, table, id})
end
@doc """
Updates the row in table `table` having the id `id`.
Returns `{:ok, previous_row} | :nf`.
"""
def update(pid, table, id, row) do
GenServer.call(pid, {:update, table, id, row})
end
@doc """
Deletes the row in table `table` having the id `id`.
Returns `{:ok, previous_row} | :nf`.
"""
def delete(pid, table, id) do
GenServer.call(pid, {:delete, table, id})
end
##########################################
# GenServer Implementation
##########################################
def init(params) do
path = Keyword.fetch!(params, :path)
Fsdb.init(path)
{:ok, path}
end
def handle_call({:create, table}, _from, path) do
{:reply, Fsdb.create(path, table), path}
end
def handle_call({:drop, table}, _from, path) do
{:reply, Fsdb.drop(path, table), path}
end
def handle_call({:list, table}, _from, path) do
{:reply, Fsdb.list(path, table), path}
end
def handle_call({:insert, table, row}, _from, path) do
{:reply, Fsdb.insert(path, table, row), path}
end
def handle_call({:save, table, id, row}, _from, path) do
{:reply, Fsdb.save(path, table, id, row), path}
end
def handle_call({:fetch, table, id}, _from, path) do
{:reply, Fsdb.fetch(path, table, id), path}
end
def handle_call({:update, table, id, row}, _from, path) do
{:reply, Fsdb.update(path, table, id, row), path}
end
def handle_call({:delete, table, id}, _from, path) do
{:reply, Fsdb.delete(path, table, id), path}
end
end