Current section

Files

Jump to
dexts lib dexts.ex
Raw

lib/dexts.ex

# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
defmodule Dexts do
@type table :: term
alias Dexts.FileError
alias Dexts.Selection
alias Dexts.Select
alias Dexts.Match
@spec info(table) :: Keyword.t | nil
def info(table) do
case :dets.info(table) do
:undefined -> nil
value -> value
end
end
@spec info(table, atom) :: term | nil
def info(table, key) do
case :dets.info(table, key) do
:undefined -> nil
value -> value
end
end
def open(path) when path |> is_binary do
:dets.open_file(String.to_char_list(path))
end
def open!(path) do
case open(path) do
{ :ok, name } ->
name
{ :error, reason } ->
raise FileError, reason: reason
end
end
def new(name, options \\ []) when name |> is_binary do
args = []
args = [{ :keypos, (options[:index] || 0) + 1 } | args]
if options[:path] do
args = [{ :file, options[:path] } | args]
end
if options[:repair] do
args = [{ :repair, options[:repair] } | args]
end
if options[:version] do
args = [{ :version, options[:version] } | args]
end
if options[:asynchronous] do
args = [{ :ram_file, true } | args]
end
if slots = options[:slots] do
if slots[:min] do
args = [{ :min_no_slots, slots[:min] } | args]
end
if slots[:max] do
args = [{ :max_no_slots, slots[:max] } | args]
end
end
if options[:save_every] do
args = [{ :auto_save, options[:save_every] } | args]
end
args = case options[:mode] || :both do
:both -> [{ :access, :read_write } | args]
:read -> [{ :access, :read } | args]
end
args = case options[:type] || :set do
:set -> [{ :type, :set } | args]
:bag -> [{ :type, :bag } | args]
:duplicate_bag -> [{ :type, :duplicate_bag } | args]
end
:dets.open_file(String.to_char_list(name), args)
end
def new!(name, options \\ []) when name |> is_binary do
case new(name, options) do
{ :ok, name } ->
name
{ :error, reason } ->
raise FileError, reason: reason
end
end
def clear(table) do
:dets.delete_all_objects(table)
end
def close(table) do
:dets.close(table)
end
def read(table, key) do
:dets.lookup(table, key)
end
def at(table, slot) do
case :dets.slot(table, slot) do
:'$end_of_table' -> nil
r -> r
end
end
@doc """
Get the first key in the given table, see `dets:first`.
"""
@spec first(table) :: any | nil
def first(table) do
case :dets.first(table) do
:"$end_of_table" -> nil
key -> key
end
end
@doc """
Get the next key in the given table, see `dets:next`.
"""
@spec next(table, any) :: any | nil
def next(table, key) do
case :dets.next(table, key) do
:"$end_of_table" -> nil
key -> key
end
end
@doc """
Get the keys in the given table.
"""
@spec keys(table) :: [term]
def keys(table) do
do_keys([], table, first(table))
end
defp do_keys(acc, _, nil) do
acc
end
defp do_keys(acc, table, key) do
[key | acc] |> do_keys(table, next(table, key))
end
@doc """
Fold the given table from the left, see `dets:foldl`.
"""
@spec foldl(table, any, (term, any -> any)) :: any
def foldl(table, acc, fun) do
:dets.foldl(fun, acc, table)
end
@doc """
Fold the given table from the right, see `dets:foldr`.
"""
@spec foldr(table, any, (term, any -> any)) :: any
def foldr(table, acc, fun) do
:dets.foldr(fun, acc, table)
end
@doc """
Select terms in the given table using a match_spec, see `dets:select`.
"""
@spec select(table, any) :: Selection.t | nil
def select(table, match_spec, options \\ [])
def select(table, match_spec, []) do
Select.new(:dets.select(table, match_spec))
end
def select(table, match_spec, limit: limit) do
Select.new(:dets.select(table, match_spec, limit))
end
@doc """
Match terms from the given table with the given pattern, see `dets:match`.
"""
@spec match(table, any) :: Selection.t | nil
def match(table, pattern) do
Match.new(:dets.match(table, pattern))
end
@doc """
Match terms from the given table with the given pattern and options, see
`dets:match`.
## Options
* `:whole` when true it returns the whole term.
* `:delete` when true it deletes the matching terms instead of returning
them.
* `:limit` the amount of elements to select at a time.
"""
@spec match(table, any | integer, Keyword.t | any) :: Selection.t | nil
def match(table, pattern, delete: true) do
:dets.match_delete(table, pattern)
end
def match(table, pattern, whole: true) do
Match.new(:dets.match_object(table, pattern))
end
def match(table, pattern, limit: limit) do
Match.new(:dets.match(table, pattern, limit))
end
def match(table, pattern, limit: limit, whole: true) do
Match.new(:dets.match_object(table, pattern, limit))
end
@doc """
Get the number of terms in the given table.
"""
@spec count(table) :: non_neg_integer
def count(table) do
info(table, :size)
end
@doc """
Count the number of terms matching the match_spec.
"""
@spec count(table, any) :: non_neg_integer
def count(table, match_spec) do
case select(table, match_spec) do
nil ->
0
selection ->
selection.values |> length
end
end
@doc """
Write the given term to the given table optionally disabling overwriting,
see `dets:insert` and `dets:insert_new`.
"""
@spec write(table, term) :: boolean
@spec write(table, term, Keyword.t) :: boolean
def write(table, object, options \\ [])
def write(table, object, overwrite: false) do
:dets.insert_new(table, object)
end
def write(table, object, []) do
:dets.insert(table, object)
end
@doc """
Synchronize the table to disk, see `dets:sync`.
"""
@spec save(table) :: :ok | { :error, term }
def save(table) do
:dets.sync(table)
end
end