Repository: whitfin/cachex (elixir)

Issue:
Rename Cache entry components to be clearer
Right now the entry is in the shape `{:key, :touched, :ttl, :value}`. Ideally this would be changed going forward to something like this: `{:key, :value, :modified, :expiration}`. 

The name renaming makes more sense, and we should also update `:ttl` options to `:expiration` too. This is a breaking change, of course. 

Pull request:
Refactor cache entry names and options
This fixes #359.

This PR will rename various options in the entry record as specified in the related issue, as well as neatening various `Cachex.Query` values to be more efficient.

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3be5b13..f6e4f28 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -41,6 +41,25 @@ jobs:
       - name: Run Tests
         run: mix test --trace
 
+  bench:
+    if: github.ref == 'refs/heads/main'
+    name: Benchmark
+    runs-on: ubuntu-latest
+    container:
+      image: elixir:1.17
+    steps:
+      - uses: actions/checkout@v3
+
+      - name: Setup Environment
+        run: |
+          epmd -daemon
+          mix local.hex --force
+          mix local.rebar --force
+          mix deps.get
+
+      - name: Run Benchmarks
+        run: mix bench
+
   coverage:
     name: Coverage
     runs-on: ubuntu-latest
diff --git a/benchmarks/main.exs b/benchmarks/main.exs
index 863b60a..ef76172 100644
--- a/benchmarks/main.exs
+++ b/benchmarks/main.exs
@@ -41,9 +41,9 @@ inputs =
     Cachex.put(name, "gad_test", "gad_value")
     Cachex.put(name, "incr_test", 0)
     Cachex.put(name, "persist_test", 0)
-    Cachex.put(name, "refresh_test", "refresh_value", ttl: one_hour)
-    Cachex.put(name, "touch_test", "touch_value", ttl: one_hour)
-    Cachex.put(name, "ttl_test", "ttl_value", ttl: one_hour)
+    Cachex.put(name, "refresh_test", "refresh_value", expire: one_hour)
+    Cachex.put(name, "touch_test", "touch_value", expire: one_hour)
+    Cachex.put(name, "ttl_test", "ttl_value", expire: one_hour)
     Cachex.put(name, "update_test", "update_value")
 
     if Keyword.get(options, :inspect) do
diff --git a/docs/features/cache-warming/reactive-warming.md b/docs/features/cache-warming/reactive-warming.md
index e07eb0d..cc6205a 100644
--- a/docs/features/cache-warming/reactive-warming.md
+++ b/docs/features/cache-warming/reactive-warming.md
@@ -60,7 +60,7 @@ Sometimes you might want to set an expiration based on a value retrieved via a f
 
 ```elixir
 Cachex.fetch(:my_cache, "key", fn ->
-  { :commit, do_something(), ttl: :timer.seconds(60) }
+  { :commit, do_something(), expire: :timer.seconds(60) }
 end)
 ```
 
diff --git a/lib/cachex.ex b/lib/cachex.ex
index 4d3fe02..ab13d7f 100644
--- a/lib/cachex.ex
+++ b/lib/cachex.ex
@@ -40,7 +40,7 @@ defmodule Cachex do
   alias Cachex.Errors
   alias Cachex.ExecutionError
   alias Cachex.Options
-  alias Cachex.Query
+  alias Cachex.Query, as: Q
   alias Cachex.Router
   alias Cachex.Services
 
@@ -721,10 +721,10 @@ defmodule Cachex do
       ...> end)
       { :commit, "yek_gnissim" }
 
-      iex> Cachex.fetch(:my_cache, "missing_key_ttl", fn(key) ->
-      ...>   { :commit, String.reverse(key), ttl: :timer.seconds(60) }
+      iex> Cachex.fetch(:my_cache, "missing_key_expires", fn(key) ->
+      ...>   { :commit, String.reverse(key), expire: :timer.seconds(60) }
       ...> end)
-      { :commit, "ltt_yek_gnissim", [ttl: 60000] }
+      { :commit, "seripxe_yek_gnissim", [expire: 60000] }
 
   """
   @spec fetch(Cachex.t(), any, function | nil, Keyword.t()) ::
@@ -1021,7 +1021,7 @@ defmodule Cachex do
 
   ## Examples
 
-      iex> Cachex.put(:my_cache, "key", "value", ttl: 1000)
+      iex> Cachex.put(:my_cache, "key", "value", expiration: 1000)
       iex> Cachex.persist(:my_cache, "key")
       { :ok, true }
 
@@ -1059,9 +1059,9 @@ defmodule Cachex do
 
   ## Options
 
-    * `:ttl`
+    * `:expire`
 
-      An expiration time to set for the provided key (time-to-live), overriding
+      An expiration value to set for the provided key (time-to-live), overriding
       any default expirations set on a cache. This value should be in milliseconds.
 
   ## Examples
@@ -1069,12 +1069,11 @@ defmodule Cachex do
       iex> Cachex.put(:my_cache, "key", "value")
       { :ok, true }
 
-      iex> Cachex.put(:my_cache, "key", "value", ttl: :timer.seconds(5))
+      iex> Cachex.put(:my_cache, "key", "value", expire: :timer.seconds(5))
       iex> Cachex.ttl(:my_cache, "key")
       { :ok, 5000 }
 
   """
-  # TODO: maybe rename TTL to be expiration?
   @spec put(Cachex.t(), any, any, Keyword.t()) :: {status, boolean}
   def put(cache, key, value, options \\ []) when is_list(options),
     do: Router.route(cache, {:put, [key, value, options]})
@@ -1089,9 +1088,9 @@ defmodule Cachex do
 
   ## Options
 
-    * `:ttl`
+    * `:expire`
 
-      An expiration time to set for the provided keys (time-to-live), overriding
+      An expiration value to set for the provided keys (time-to-live), overriding
       any default expirations set on a cache. This value should be in milliseconds.
 
   ## Examples
@@ -1099,12 +1098,11 @@ defmodule Cachex do
       iex> Cachex.put_many(:my_cache, [ { "key", "value" } ])
       { :ok, true }
 
-      iex> Cachex.put_many(:my_cache, [ { "key", "value" } ], ttl: :timer.seconds(5))
+      iex> Cachex.put_many(:my_cache, [ { "key", "value" } ], expire: :timer.seconds(5))
       iex> Cachex.ttl(:my_cache, "key")
       { :ok, 5000 }
 
   """
-  # TODO: maybe rename TTL to be expiration?
   @spec put_many(Cachex.t(), [{any, any}], Keyword.t()) :: {status, boolean}
   def put_many(cache, pairs, options \\ [])
       when is_list(pairs) and is_list(options),
@@ -1120,7 +1118,7 @@ defmodule Cachex do
 
   ## Examples
 
-      iex> Cachex.put(:my_cache, "my_key", "my_value", ttl: :timer.seconds(5))
+      iex> Cachex.put(:my_cache, "my_key", "my_value", expire: :timer.seconds(5))
       iex> Process.sleep(4)
       iex> Cachex.ttl(:my_cache, "my_key")
       { :ok, 1000 }
@@ -1251,21 +1249,21 @@ defmodule Cachex do
         {:entry, "c", 1519015805679, nil, 3},
         {:entry, "a", 1519015794445, nil, 1}]
 
-      iex> query = Cachex.Query.where(true, :key)
+      iex> query = Cachex.Query.create(output: :key)
       iex> :my_cache |> Cachex.stream!(query) |> Enum.to_list
       ["b", "c", "a"]
 
-      iex> query = Cachex.Query.where(true, :value)
+      iex> query = Cachex.Query.create(output: :value)
       iex> :my_cache |> Cachex.stream!(query) |> Enum.to_list
       [2, 3, 1]
 
-      iex> query = Cachex.Query.where(true, { :key, :value })
+      iex> query = Cachex.Query.create(output: {:key, :value})
       iex> :my_cache |> Cachex.stream!(query) |> Enum.to_list
       [{"b", 2}, {"c", 3}, {"a", 1}]
 
   """
   @spec stream(Cachex.t(), any, Keyword.t()) :: {status, Enumerable.t()}
-  def stream(cache, query \\ Query.where(true), options \\ [])
+  def stream(cache, query \\ Q.create(where: Q.unexpired()), options \\ [])
       when is_list(options),
       do: Router.route(cache, {:stream, [query, options]})
 
diff --git a/lib/cachex/actions/count.ex b/lib/cachex/actions/count.ex
index 6e431b7..b26e6ec 100644
--- a/lib/cachex/actions/count.ex
+++ b/lib/cachex/actions/count.ex
@@ -20,6 +20,10 @@ defmodule Cachex.Actions.Count do
   means that any items set to be removed in the next purge will not be added
   to the count. Lazy expiration does not apply to this call.
   """
-  def execute(cache(name: name), _options),
-    do: {:ok, :ets.select_count(name, Query.unexpired(true))}
+  def execute(cache(name: name), _options) do
+    filter = Query.unexpired()
+    clause = Query.create(where: filter, output: true)
+
+    {:ok, :ets.select_count(name, clause)}
+  end
 end
diff --git a/lib/cachex/actions/expire.ex b/lib/cachex/actions/expire.ex
index f810b69..6746300 100644
--- a/lib/cachex/actions/expire.ex
+++ b/lib/cachex/actions/expire.ex
@@ -33,8 +33,11 @@ defmodule Cachex.Actions.Expire do
   def execute(cache() = cache, key, expiration, _options) do
     Locksmith.write(cache, [key], fn ->
       case expiration > -1 do
-        true -> Actions.update(cache, key, entry_mod_now(ttl: expiration))
-        false -> Cachex.del(cache, key, const(:purge_override))
+        true ->
+          Actions.update(cache, key, entry_mod_now(expiration: expiration))
+
+        false ->
+          Cachex.del(cache, key, const(:purge_override))
       end
     end)
   end
diff --git a/lib/cachex/actions/import.ex b/lib/cachex/actions/import.ex
index aa8045e..c816963 100644
--- a/lib/cachex/actions/import.ex
+++ b/lib/cachex/actions/import.ex
@@ -26,25 +26,24 @@ defmodule Cachex.Actions.Import do
   #
   # As this is a direct import, we just use `Cachex.put/4` with the provided
   # key and value from the existing entry record - nothing special here.
-  defp import(cache, entry(key: k, ttl: nil, value: v), _time),
+  defp import(cache, entry(key: k, expiration: nil, value: v), _t),
     do: {:ok, true} = Cachex.put(cache, k, v, const(:notify_false))
 
   # Skips over entries which have already expired.
   #
-  # This occurs in the case there was an existing touch time and TTL, and
-  # the expiration time would already have passed (so there's no point in
+  # This occurs in the case there was an existing modification time and expiration
+  # but the expiration time would already have passed (so there's no point in
   # adding the record to the cache just to throw it away in future).
-  defp import(_cache, entry(touched: t1, ttl: t2), time)
-       when t1 + t2 < time,
-       do: nil
+  defp import(_cache, entry(modified: m, expiration: e), t) when m + e < t,
+    do: nil
 
   # Imports an entry, using the current time to offset the TTL value.
   #
   # This is required to shift the TTLs set in a backup to match the current
   # import time, so that the rest of the lifetime of the key is the same. If
   # we didn't do this, the key would live longer in the cache than intended.
-  defp import(cache, entry(key: k, touched: t1, ttl: t2, value: v), time) do
-    opts = const(:notify_false) ++ [ttl: t1 + t2 - time]
+  defp import(cache, entry(key: k, modified: m, expiration: e, value: v), t) do
+    opts = const(:notify_false) ++ [expire: m + e - t]
     {:ok, true} = Cachex.put(cache, k, v, opts)
   end
 end
diff --git a/lib/cachex/actions/incr.ex b/lib/cachex/actions/incr.ex
index b7ee83d..1c8299f 100644
--- a/lib/cachex/actions/incr.ex
+++ b/lib/cachex/actions/incr.ex
@@ -31,7 +31,7 @@ defmodule Cachex.Actions.Incr do
     initial = Options.get(options, :initial, &is_integer/1, 0)
     expiry = Janitor.expiration(cache, nil)
 
-    default = entry_now(key: key, ttl: expiry, value: initial)
+    default = entry_now(key: key, expiration: expiry, value: initial)
 
     Locksmith.write(cache, [key], fn ->
       try do
diff --git a/lib/cachex/actions/inspect.ex b/lib/cachex/actions/inspect.ex
index 44902a7..5daa117 100644
--- a/lib/cachex/actions/inspect.ex
+++ b/lib/cachex/actions/inspect.ex
@@ -82,16 +82,24 @@ defmodule Cachex.Actions.Inspect do
   # The number of entries returned represents the number of records which will
   # be removed on the next run of the Janitor service. It does not track the
   # number of expired records which have already been purged or removed.
-  def execute(cache(name: name), {:expired, :count}, _options),
-    do: {:ok, :ets.select_count(name, Query.expired(true))}
+  def execute(cache(name: name), {:expired, :count}, _options) do
+    filter = Query.expired()
+    clause = Query.create(where: filter, output: true)
+
+    {:ok, :ets.select_count(name, clause)}
+  end
 
   # Returns the keys of expired entries currently inside the cache.
   #
   # This is essentially the same as the definition above, except that it will
   # return the list of entry keys rather than just a count. Naturally this is
   # an expensive call and should really only be used when debugging.
-  def execute(cache(name: name), {:expired, :keys}, _options),
-    do: {:ok, :ets.select(name, Query.expired(:key))}
+  def execute(cache(name: name), {:expired, :keys}, _options) do
+    filter = Query.expired()
+    clause = Query.create(where: filter, output: :key)
+
+    {:ok, :ets.select(name, clause)}
+  end
 
   # Returns information about the last run of the Janitor service.
   #
diff --git a/lib/cachex/actions/keys.ex b/lib/cachex/actions/keys.ex
index 031e6e1..7edb8ae 100644
--- a/lib/cachex/actions/keys.ex
+++ b/lib/cachex/actions/keys.ex
@@ -23,6 +23,10 @@ defmodule Cachex.Actions.Keys do
   that any entries currently inside the cache which are scheduled to be removed
   will not be included.
   """
-  def execute(cache(name: name), _options),
-    do: {:ok, :ets.select(name, Query.where(true, :key))}
+  def execute(cache(name: name), _options) do
+    filter = Query.unexpired()
+    clause = Query.create(where: filter, output: :key)
+
+    {:ok, :ets.select(name, clause)}
+  end
 end
diff --git a/lib/cachex/actions/purge.ex b/lib/cachex/actions/purge.ex
index 820a553..7ab74c4 100644
--- a/lib/cachex/actions/purge.ex
+++ b/lib/cachex/actions/purge.ex
@@ -29,7 +29,10 @@ defmodule Cachex.Actions.Purge do
   """
   def execute(cache(name: name) = cache, _options) do
     Locksmith.transaction(cache, [], fn ->
-      {:ok, :ets.select_delete(name, Query.expired(true))}
+      filter = Query.expired()
+      clause = Query.create(where: filter, output: true)
+
+      {:ok, :ets.select_delete(name, clause)}
     end)
   end
 end
diff --git a/lib/cachex/actions/put.ex b/lib/cachex/actions/put.ex
index 5768cf2..06c2e2a 100644
--- a/lib/cachex/actions/put.ex
+++ b/lib/cachex/actions/put.ex
@@ -26,10 +26,10 @@ defmodule Cachex.Actions.Put do
   inside a lock aware context to avoid clashing with other processes.
   """
   def execute(cache() = cache, key, value, options) do
-    ttlval = Options.get(options, :ttl, &is_integer/1)
-    expiry = Janitor.expiration(cache, ttlval)
+    expiration = Options.get(options, :expire, &is_integer/1)
+    expiration = Janitor.expiration(cache, expiration)
 
-    record = entry_now(key: key, ttl: expiry, value: value)
+    record = entry_now(key: key, expiration: expiration, value: value)
 
     Locksmith.write(cache, [key], fn ->
       Actions.write(cache, record)
diff --git a/lib/cachex/actions/put_many.ex b/lib/cachex/actions/put_many.ex
index f617870..5c61478 100644
--- a/lib/cachex/actions/put_many.ex
+++ b/lib/cachex/actions/put_many.ex
@@ -28,10 +28,10 @@ defmodule Cachex.Actions.PutMany do
   inside a lock aware context to avoid clashing with other processes.
   """
   def execute(cache() = cache, pairs, options) do
-    ttlval = Options.get(options, :ttl, &is_integer/1)
-    expiry = Janitor.expiration(cache, ttlval)
+    expiration = Options.get(options, :expire, &is_integer/1)
+    expiration = Janitor.expiration(cache, expiration)
 
-    with {:ok, keys, entries} <- map_entries(expiry, pairs, [], []) do
+    with {:ok, keys, entries} <- map_entries(expiration, pairs, [], []) do
       Locksmith.write(cache, keys, fn ->
         Actions.write(cache, entries)
       end)
@@ -50,17 +50,17 @@ defmodule Cachex.Actions.PutMany do
   #
   # If an unexpected pair is hit, an error will be returned and no
   # values will be written to the backing table.
-  defp map_entries(ttl, [{key, value} | pairs], keys, entries) do
-    entry = entry_now(key: key, ttl: ttl, value: value)
-    map_entries(ttl, pairs, [key | keys], [entry | entries])
+  defp map_entries(exp, [{key, value} | pairs], keys, entries) do
+    entry = entry_now(key: key, expiration: exp, value: value)
+    map_entries(exp, pairs, [key | keys], [entry | entries])
   end
 
-  defp map_entries(_ttl, [], [], _entries),
+  defp map_entries(_exp, [], [], _entries),
     do: {:ok, false}
 
-  defp map_entries(_ttl, [], keys, entries),
+  defp map_entries(_exp, [], keys, entries),
     do: {:ok, keys, entries}
 
-  defp map_entries(_ttl, _inv, _keys, _entries),
+  defp map_entries(_exp, _inv, _keys, _entries),
     do: error(:invalid_pairs)
 end
diff --git a/lib/cachex/actions/refresh.ex b/lib/cachex/actions/refresh.ex
index 8a94734..7697d2a 100644
--- a/lib/cachex/actions/refresh.ex
+++ b/lib/cachex/actions/refresh.ex
@@ -3,8 +3,8 @@ defmodule Cachex.Actions.Refresh do
   # Command module to allow refreshing an expiration value.
   #
   # Refreshing an expiration is the notion of resetting an expiration time
-  # as if it were just set. This is done by updating the touched time (as
-  # this is used to calculate expiration offsets).
+  # as if it were just set. This is done by updating the modification time
+  # (as this is used to calculate expiration offsets).
   #
   # The main advantage of this command is the ability to refresh an existing
   # expiration without knowing in advance what it was previously set to.
@@ -22,8 +22,8 @@ defmodule Cachex.Actions.Refresh do
   Refreshes an expiration on a cache entry.
 
   If the entry currently has no expiration set, it is left unset. Otherwise the
-  touch time of the entry is updated to the current time (as entry expiration is
-  a function of touched time and expiration time).
+  modified time of the entry is updated to the current time (as entry expiration is
+  a function of modified time and expiration time).
 
   This operates inside a lock aware context to avoid clashing with other operations
   on the same key during execution.
diff --git a/lib/cachex/actions/stream.ex b/lib/cachex/actions/stream.ex
index ce31faa..0252746 100644
--- a/lib/cachex/actions/stream.ex
+++ b/lib/cachex/actions/stream.ex
@@ -12,7 +12,7 @@ defmodule Cachex.Actions.Stream do
   import Cachex.Spec
 
   # our test record for testing matches when a user provides a spec
-  @test entry(key: "key", touched: now(), ttl: 1000, value: "value")
+  @test entry(key: "key", modified: now(), expiration: 1000, value: "value")
 
   ##############
   # Public API #
diff --git a/lib/cachex/actions/touch.ex b/lib/cachex/actions/touch.ex
index d8b67e1..47fa360 100644
--- a/lib/cachex/actions/touch.ex
+++ b/lib/cachex/actions/touch.ex
@@ -29,7 +29,7 @@ defmodule Cachex.Actions.Touch do
     Locksmith.transaction(cache, [key], fn ->
       cache
       |> Ttl.execute(key, [])
-      |> handle_ttl(cache, key)
+      |> handle_expiration(cache, key)
     end)
   end
 
@@ -42,13 +42,13 @@ defmodule Cachex.Actions.Touch do
   # If the expiration if unset, we update just the touch time insude the entry
   # as we don't have to account for the offset. If an expiration is set, we
   # also update the expiration on the record to be the returned offset.
-  defp handle_ttl({:ok, value}, cache, key) do
+  defp handle_expiration({:ok, value}, cache, key) do
     Actions.update(
       cache,
       key,
       case value do
         nil -> entry_mod_now()
-        ttl -> entry_mod_now(ttl: ttl)
+        exp -> entry_mod_now(expiration: exp)
       end
     )
   end
diff --git a/lib/cachex/actions/ttl.ex b/lib/cachex/actions/ttl.ex
index d47879c..0d8625e 100644
--- a/lib/cachex/actions/ttl.ex
+++ b/lib/cachex/actions/ttl.ex
@@ -24,8 +24,8 @@ defmodule Cachex.Actions.Ttl do
   """
   def execute(cache() = cache, key, _options) do
     case Actions.read(cache, key) do
-      entry(touched: touched, ttl: ttl) when not is_nil(ttl) ->
-        {:ok, touched + ttl - now()}
+      entry(modified: modified, expiration: exp) when not is_nil(exp) ->
+        {:ok, modified + exp - now()}
 
       _anything_else ->
         {:ok, nil}
diff --git a/lib/cachex/options.ex b/lib/cachex/options.ex
index 4c77107..ed87d49 100644
--- a/lib/cachex/options.ex
+++ b/lib/cachex/options.ex
@@ -38,9 +38,23 @@ defmodule Cachex.Options do
 
   If the value satisfies the condition provided, it will be returned. Otherwise
   the default value provided is returned instead. Used for basic validations.
+
+  If multiple keys are provided they will be tried in order and the first
+  matching value will be returned (used for backwards compatibility).
   """
   @spec get(Keyword.t(), atom, (any -> boolean), any) :: any
-  def get(options, key, condition, default \\ nil) do
+  def get(options, keys, condition, default \\ nil)
+
+  def get(options, keys, condition, default) when is_list(keys) do
+    Enum.reduce_while(keys, default, fn key, ^default ->
+      case get(options, key, condition, default) do
+        ^default -> {:cont, default}
+        parsed -> {:halt, parsed}
+      end
+    end)
+  end
+
+  def get(options, key, condition, default) do
     transform(options, key, fn val ->
       try do
         (condition.(val) && val) || default
diff --git a/lib/cachex/policy/lrw.ex b/lib/cachex/policy/lrw.ex
index 3117021..52e8f6a 100644
--- a/lib/cachex/policy/lrw.ex
+++ b/lib/cachex/policy/lrw.ex
@@ -4,7 +4,7 @@ defmodule Cachex.Policy.LRW do
 
   This module provides general utilities for implementing an eviction policy for
   Cachex which will evict the least-recently written entries from the cache. This
-  is determined by the touched time inside each cache record, which means that we
+  is determined by the modified time inside each cache record, which means that we
   don't have to store any additional tables to keep track of access time.
 
   There are several options recognised by this policy which can be passed inside the
@@ -47,7 +47,7 @@ defmodule Cachex.Policy.LRW do
   alias Cachex.Services.Informant
 
   # compile our match to avoid recalculating
-  @ets_match Query.raw(true, {:key, :touched})
+  @ets_match Query.create(output: {:key, :modified})
 
   ####################
   # Policy Behaviour #
diff --git a/lib/cachex/query.ex b/lib/cachex/query.ex
index 20383d2..03263ac 100644
--- a/lib/cachex/query.ex
+++ b/lib/cachex/query.ex
@@ -13,62 +13,105 @@ defmodule Cachex.Query do
   """
   import Cachex.Spec
 
+  # raw query header
+  @header entry()
+          |> entry()
+          |> Enum.with_index(1)
+          |> Enum.map(fn {_, idx} -> :"$#{idx}" end)
+          |> Enum.reverse()
+          |> Enum.concat([:_])
+          |> Enum.reverse()
+          |> List.to_tuple()
+
   ##############
   # Public API #
   ##############
 
   @doc """
-  Creates a query to retrieve all expired records.
-  """
-  @spec expired(any) :: [{tuple, [tuple], [any]}]
-  def expired(output \\ :"$_"),
-    do: raw(expired_clause(), output)
+  Create a query specification for a cache.
 
-  @doc """
-  Creates a match condition for expired records.
-  """
-  @spec expired_clause :: tuple
-  def expired_clause,
-    do: {:not, unexpired_clause()}
+  This is a convenience binding to ETS select specifications, so please see
+  the appropriate documentation for any additional information on how to (e.g.)
+  format filter clauses and outputs.
+
+  ## Options
+
+    * `:expired`
+
+      Whether to filter expired records or not, with the default being no
+      filtering. Setting this to `true` will only retrieve expired records,
+      while setting to `false` will only retrieve unexpired records.
+
+    * `:output`
+
+      The query output format, which defaults to `:entry` (retrieving the entire
+      cache entry). You can provide any of the entry record fields, with bindings
+      such as tuples (`{:key, :value}`) or lists `[:key, :value]` or as a single
+      value (`:key`).
+
+    * `:where`
+
+      An ETS filter condition used to locate records in the table. This defaults to
+      retrieving all records, and is automatically joined with the value of the
+      `:expired` flag for convenience.
 
-  @doc """
-  Creates a raw query, ignoring expiration.
   """
-  @spec raw(any, any) :: [{tuple, [tuple], [any]}]
-  def raw(condition, output \\ :"$_"),
+  @spec create(options :: Keyword.t()) :: [{tuple, [tuple], [any]}]
+  def create(options \\ []),
     do: [
       {
-        {:_, :"$1", :"$2", :"$3", :"$4"},
-        [map_clauses(condition)],
-        [clean_return(map_clauses(output))]
+        @header,
+        [
+          options
+          |> Keyword.get(:where, true)
+          |> map_clauses
+        ],
+        [
+          options
+          |> Keyword.get(:output, :entry)
+          |> map_clauses
+          |> clean_return
+        ]
       }
     ]
 
   @doc """
-  Creates a query to retrieve all unexpired records.
-  """
-  @spec unexpired(any) :: [{tuple, [tuple], [any]}]
-  def unexpired(output \\ :"$_"),
-    do: raw(unexpired_clause(), output)
+  Create a filter against expired records in a cache.
 
-  @doc """
-  Creates a match condition for unexpired records.
+  This function accepts a subfilter to join to create more complex filters.
   """
-  @spec unexpired_clause :: tuple
-  def unexpired_clause,
-    do: {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, now()}}
+  @spec expired(filter :: boolean() | tuple()) :: tuple
+  def expired(filter \\ nil),
+    do: wrap_condition(filter, {:not, unexpired()})
 
   @doc """
-  Creates an expiration-aware query.
+  Create a filter against unexpired records in a cache.
+
+  This function accepts a subfilter to join to create more complex filters.
   """
-  @spec where(any, any) :: [{tuple, [tuple], [any]}]
-  def where(condition, output \\ :"$_"),
-    do: raw({:andalso, unexpired_clause(), condition}, output)
+  @spec unexpired(filter :: boolean() | tuple()) :: tuple
+  def unexpired(filter \\ nil),
+    do:
+      wrap_condition(
+        filter,
+        {:orelse, {:==, map_clauses(:expiration), nil},
+         {:>, {:+, map_clauses(:modified), map_clauses(:expiration)}, now()}}
+      )
 
   ###############
   # Private API #
   ###############
 
+  # Sanitizes a returning value clause.
+  #
+  # This will just wrap any non-single element Tuples being returned as
+  # this is required in order to provide valid return formats.
+  defp clean_return(tpl) when tuple_size(tpl) > 1,
+    do: {tpl}
+
+  defp clean_return(val),
+    do: val
+
   # Recursively replaces all entry tags in a clause value.
   #
   # This allows the use of entry fields, such as `:key` as references in
@@ -85,23 +128,24 @@ defmodule Cachex.Query do
     do: Enum.map(list, &map_clauses/1)
 
   # basic entry field name substitution
-  for key <- Keyword.keys(entry(entry())),
-      do:
-        defp(map_clauses(unquote(key)),
-          do: :"$#{entry(unquote(key))}"
-        )
+  for key <- Keyword.keys(entry(entry())) do
+    defp map_clauses(unquote(key)),
+      do: :"$#{entry(unquote(key))}"
+  end
+
+  # whole cache entry
+  defp map_clauses(:entry),
+    do: :"$_"
 
   # no-op, already valid
-  defp map_clauses(field),
-    do: field
+  defp map_clauses(value),
+    do: value
 
-  # Sanitizes a returning value clause.
-  #
-  # This will just wrap any non-single element Tuples being returned as
-  # this is required in order to provide valid return formats.
-  defp clean_return(tpl) when tuple_size(tpl) > 1,
-    do: {tpl}
+  # Wrap a where clause with a new condition only if the whre clause
+  # isn't simply true; if so, defer to the provided condition.
+  defp wrap_condition(filter, subfilter) when filter in [nil, true],
+    do: subfilter
 
-  defp clean_return(val),
-    do: val
+  defp wrap_condition(filter, subfilter),
+    do: {:andalso, subfilter, filter}
 end
diff --git a/lib/cachex/services/janitor.ex b/lib/cachex/services/janitor.ex
index 631f83d..0122c48 100644
--- a/lib/cachex/services/janitor.ex
+++ b/lib/cachex/services/janitor.ex
@@ -61,8 +61,8 @@ defmodule Cachex.Services.Janitor do
   This will not cache lazy expiration settings into account.
   """
   @spec expired?(Cachex.Spec.entry()) :: boolean
-  def expired?(entry(touched: touched, ttl: ttl)) when is_number(ttl),
-    do: touched + ttl < now()
+  def expired?(entry(modified: modified, expiration: exp)) when is_number(exp),
+    do: modified + exp < now()
 
   def expired?(_entry),
     do: false
@@ -103,7 +103,7 @@ defmodule Cachex.Services.Janitor do
   #
   # This will drop to the ETS level and use a select to match documents which
   # need to be removed; they are then deleted by ETS at very high speeds.
-  def handle_info(:ttl_check, {cache(name: name), _last}) do
+  def handle_info(:purge, {cache(name: name), _last}) do
     start_time = now()
     new_caches = Overseer.retrieve(name)
 
@@ -133,7 +133,7 @@ defmodule Cachex.Services.Janitor do
   # Schedules a check to occur after the designated interval. Once scheduled,
   # returns the state - this is just sugar for pipelining with a state.
   defp schedule_check(cache(expiration: expiration(interval: interval)) = cache) do
-    :erlang.send_after(interval, self(), :ttl_check)
+    :erlang.send_after(interval, self(), :purge)
     cache
   end
 end
diff --git a/lib/cachex/spec.ex b/lib/cachex/spec.ex
index 6256e25..1d1eab1 100644
--- a/lib/cachex/spec.ex
+++ b/lib/cachex/spec.ex
@@ -58,9 +58,9 @@ defmodule Cachex.Spec do
   @type entry ::
           record(:entry,
             key: any,
-            touched: number,
-            ttl: number,
-            value: any
+            value: any,
+            modified: number,
+            expiration: number
           )
 
   # Helper type for entry types
@@ -174,9 +174,9 @@ defmodule Cachex.Spec do
   """
   defrecord :entry,
     key: nil,
-    touched: nil,
-    ttl: nil,
-    value: nil
+    value: nil,
+    modified: nil,
+    expiration: nil
 
   @doc """
   Creates an expiration record from the provided values.
@@ -442,22 +442,22 @@ defmodule Cachex.Spec do
   Generates a list of ETS modification Tuples with an updated touch time.
 
   This will pass the arguments through and behave exactly as `entry_mod/1`
-  except that it will automatically update the `:touched` field in the entry
+  except that it will automatically update the `:modified` field in the entry
   to the current time.
   """
   @spec entry_mod_now([{atom, any}]) :: [{integer, any}]
   defmacro entry_mod_now(pairs \\ []),
-    do: quote(do: entry_mod(unquote([touched: quote(do: now())] ++ pairs)))
+    do: quote(do: entry_mod(unquote([modified: quote(do: now())] ++ pairs)))
 
   @doc """
   Creates an entry record with an updated touch time.
 
-  This delegates through to `entry/1`, but ensures that the `:touched` field is
+  This delegates through to `entry/1`, but ensures that the `:modified` field is
   set to the current time as a millisecond timestamp.
   """
   @spec entry_now([{atom, any}]) :: [{integer, any}]
   defmacro entry_now(pairs \\ []),
-    do: quote(do: entry(unquote([touched: quote(do: now())] ++ pairs)))
+    do: quote(do: entry(unquote([modified: quote(do: now())] ++ pairs)))
 
   ############
   # Services #
diff --git a/lib/cachex/spec/validator.ex b/lib/cachex/spec/validator.ex
index 685e120..79e03fc 100644
--- a/lib/cachex/spec/validator.ex
+++ b/lib/cachex/spec/validator.ex
@@ -48,8 +48,8 @@ defmodule Cachex.Spec.Validator do
   # This only has to validate the touch time and ttl values inside a record,
   # as the key and value can be of any type (including nil). The touch time
   # and ttl values must be integers if set, and the ttl value can be nil.
-  def valid?(:entry, entry(touched: touched, ttl: ttl)),
-    do: is_positive_integer(touched) and nillable?(ttl, &is_positive_integer/1)
+  def valid?(:entry, entry(modified: modified, expiration: exp)),
+    do: is_positive_integer(modified) and nillable?(exp, &is_positive_integer/1)
 
   # Validates an expiration specification record.
   #
diff --git a/lib/cachex/stats.ex b/lib/cachex/stats.ex
index fe5d3b4..f073b84 100644
--- a/lib/cachex/stats.ex
+++ b/lib/cachex/stats.ex
@@ -94,7 +94,7 @@ defmodule Cachex.Stats do
   def handle_notify(_action, {:error, _result}, stats),
     do: {:ok, stats}
 
-  # coveralls-ignore-end
+  # coveralls-ignore-stop
 
   @doc false
   # Registers an action against the stats container.


Test patch:
diff --git a/test/cachex/actions/count_test.exs b/test/cachex/actions/count_test.exs
index 32caf89..b5885f0 100644
--- a/test/cachex/actions/count_test.exs
+++ b/test/cachex/actions/count_test.exs
@@ -16,9 +16,9 @@ defmodule Cachex.Actions.CountTest do
     {:ok, true} = Cachex.put(cache, 3, 3)
 
     # add some expired items
-    {:ok, true} = Cachex.put(cache, 4, 4, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 5, 5, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 6, 6, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 4, 4, expire: 1)
+    {:ok, true} = Cachex.put(cache, 5, 5, expire: 1)
+    {:ok, true} = Cachex.put(cache, 6, 6, expire: 1)
 
     # let entries expire
     :timer.sleep(2)
diff --git a/test/cachex/actions/exists_test.exs b/test/cachex/actions/exists_test.exs
index 24e69d3..614dcae 100644
--- a/test/cachex/actions/exists_test.exs
+++ b/test/cachex/actions/exists_test.exs
@@ -13,7 +13,7 @@ defmodule Cachex.Actions.ExistsTest do
 
     # add some keys to the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
 
     # let TTLs clear
     :timer.sleep(2)
diff --git a/test/cachex/actions/expire_at_test.exs b/test/cachex/actions/expire_at_test.exs
index 3dd0188..f7ee76d 100644
--- a/test/cachex/actions/expire_at_test.exs
+++ b/test/cachex/actions/expire_at_test.exs
@@ -14,8 +14,8 @@ defmodule Cachex.Actions.ExpireAtTest do
 
     # add some keys to the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 10)
-    {:ok, true} = Cachex.put(cache, 3, 3, ttl: 10)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 10)
+    {:ok, true} = Cachex.put(cache, 3, 3, expire: 10)
 
     # clear messages
     TestUtils.flush()
diff --git a/test/cachex/actions/expire_test.exs b/test/cachex/actions/expire_test.exs
index 767b8dc..8d91bed 100644
--- a/test/cachex/actions/expire_test.exs
+++ b/test/cachex/actions/expire_test.exs
@@ -14,8 +14,8 @@ defmodule Cachex.Actions.ExpireTest do
 
     # add some keys to the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 10)
-    {:ok, true} = Cachex.put(cache, 3, 3, ttl: 10)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 10)
+    {:ok, true} = Cachex.put(cache, 3, 3, expire: 10)
 
     # clear messages
     TestUtils.flush()
diff --git a/test/cachex/actions/fetch_test.exs b/test/cachex/actions/fetch_test.exs
index c7e0dfe..7089f17 100644
--- a/test/cachex/actions/fetch_test.exs
+++ b/test/cachex/actions/fetch_test.exs
@@ -23,7 +23,7 @@ defmodule Cachex.Actions.FetchTest do
 
     # set some keys in the cache
     {:ok, true} = Cachex.put(cache1, "key1", 1)
-    {:ok, true} = Cachex.put(cache1, "key2", 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache1, "key2", 2, expire: 1)
 
     # wait for the TTL to pass
     :timer.sleep(2)
@@ -143,7 +143,7 @@ defmodule Cachex.Actions.FetchTest do
     cache = TestUtils.create_cache()
 
     # create a fallback with an expiration
-    purged = [ttl: 60000]
+    purged = [expire: 60000]
     fb_opt = &{:commit, String.reverse(&1), purged}
 
     # fetch our key using our fallback
diff --git a/test/cachex/actions/get_and_update_test.exs b/test/cachex/actions/get_and_update_test.exs
index a9734b2..c410f1e 100644
--- a/test/cachex/actions/get_and_update_test.exs
+++ b/test/cachex/actions/get_and_update_test.exs
@@ -13,8 +13,8 @@ defmodule Cachex.Actions.GetAndUpdateTest do
 
     # set some keys in the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 4, 4, ttl: 1000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
+    {:ok, true} = Cachex.put(cache, 4, 4, expire: 1000)
     {:ok, true} = Cachex.put(cache, 5, 5)
     {:ok, true} = Cachex.put(cache, 6, 6)
 
diff --git a/test/cachex/actions/get_test.exs b/test/cachex/actions/get_test.exs
index c9ad5c8..f83252c 100644
--- a/test/cachex/actions/get_test.exs
+++ b/test/cachex/actions/get_test.exs
@@ -14,7 +14,7 @@ defmodule Cachex.Actions.GetTest do
 
     # set some keys in the cache
     {:ok, true} = Cachex.put(cache1, 1, 1)
-    {:ok, true} = Cachex.put(cache1, 2, 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache1, 2, 2, expire: 1)
 
     # wait for the TTL to pass
     :timer.sleep(2)
diff --git a/test/cachex/actions/import_test.exs b/test/cachex/actions/import_test.exs
index 14de395..7e777d4 100644
--- a/test/cachex/actions/import_test.exs
+++ b/test/cachex/actions/import_test.exs
@@ -11,8 +11,8 @@ defmodule Cachex.Actions.ImportTest do
 
     # add some cache entries
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 3, 3, ttl: 10_000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
+    {:ok, true} = Cachex.put(cache, 3, 3, expire: 10_000)
 
     # export the cache to a list
     result1 = Cachex.export(cache)
diff --git a/test/cachex/actions/inspect_test.exs b/test/cachex/actions/inspect_test.exs
index f408fd2..bb0a835 100644
--- a/test/cachex/actions/inspect_test.exs
+++ b/test/cachex/actions/inspect_test.exs
@@ -10,7 +10,7 @@ defmodule Cachex.Actions.InspectTest do
 
     # set several values in the cache
     for x <- 1..3 do
-      {:ok, true} = Cachex.put(cache, "key#{x}", "value#{x}", ttl: 1)
+      {:ok, true} = Cachex.put(cache, "key#{x}", "value#{x}", expire: 1)
     end
 
     # make sure they expire
@@ -106,19 +106,20 @@ defmodule Cachex.Actions.InspectTest do
     ctime = now()
 
     # set a cache record
-    {:ok, true} = Cachex.put(cache, 1, "one", ttl: 1000)
+    {:ok, true} = Cachex.put(cache, 1, "one", expire: 1000)
 
     # fetch some records
     record1 = Cachex.inspect(cache, {:entry, 1})
     record2 = Cachex.inspect(cache, {:entry, 2})
 
     # break down the first record
-    {:ok, {:entry, key, touched, ttl, value}} = record1
+    {:ok, entry(key: key, modified: mod, expiration: exp, value: value)} =
+      record1
 
     # verify the first record
     assert(key == 1)
-    assert_in_delta(touched, ctime, 2)
-    assert(ttl == 1000)
+    assert_in_delta(mod, ctime, 2)
+    assert(exp == 1000)
     assert(value == "one")
 
     # the second should be nil
diff --git a/test/cachex/actions/invoke_test.exs b/test/cachex/actions/invoke_test.exs
index e1a093d..e7438f2 100644
--- a/test/cachex/actions/invoke_test.exs
+++ b/test/cachex/actions/invoke_test.exs
@@ -20,7 +20,7 @@ defmodule Cachex.Actions.InvokeTest do
     {:ok, true} = Cachex.put(cache, "list", [1, 2, 3, 4])
 
     # retrieve the raw record
-    {:entry, "list", touched, nil, _val} =
+    entry(key: "list", modified: modified) =
       Cachex.inspect!(cache, {:entry, "list"})
 
     # execute some custom commands
@@ -35,11 +35,9 @@ defmodule Cachex.Actions.InvokeTest do
     assert(rpop1 == {:ok, 4})
     assert(rpop2 == {:ok, 3})
 
-    # retrieve the raw record again
-    inspect1 = Cachex.inspect!(cache, {:entry, "list"})
-
-    # verify the touched time was unchanged
-    assert(inspect1 == {:entry, "list", touched, nil, []})
+    # verify the modified time was unchanged
+    assert Cachex.inspect!(cache, {:entry, "list"}) ==
+             entry(key: "list", modified: modified, value: [])
 
     # pop some extras to test avoiding writes
     lpop3 = Cachex.invoke(cache, :lpop, "list")
diff --git a/test/cachex/actions/keys_test.exs b/test/cachex/actions/keys_test.exs
index 57fff30..7d9c3b2 100644
--- a/test/cachex/actions/keys_test.exs
+++ b/test/cachex/actions/keys_test.exs
@@ -18,9 +18,9 @@ defmodule Cachex.Actions.KeysTest do
     {:ok, true} = Cachex.put(cache, 3, 3)
 
     # add some expired items
-    {:ok, true} = Cachex.put(cache, 4, 4, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 5, 5, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 6, 6, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 4, 4, expire: 1)
+    {:ok, true} = Cachex.put(cache, 5, 5, expire: 1)
+    {:ok, true} = Cachex.put(cache, 6, 6, expire: 1)
 
     # let entries expire
     :timer.sleep(2)
diff --git a/test/cachex/actions/load_test.exs b/test/cachex/actions/load_test.exs
index 621acdd..096c739 100644
--- a/test/cachex/actions/load_test.exs
+++ b/test/cachex/actions/load_test.exs
@@ -15,8 +15,8 @@ defmodule Cachex.Actions.LoadTest do
 
     # add some cache entries
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 3, 3, ttl: 10_000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
+    {:ok, true} = Cachex.put(cache, 3, 3, expire: 10_000)
 
     # create a local path to write to
     path = Path.join(tmp, TestUtils.gen_rand_bytes(8))
diff --git a/test/cachex/actions/persist_test.exs b/test/cachex/actions/persist_test.exs
index 531f35f..553d1d6 100644
--- a/test/cachex/actions/persist_test.exs
+++ b/test/cachex/actions/persist_test.exs
@@ -13,7 +13,7 @@ defmodule Cachex.Actions.PersistTest do
 
     # add some keys to the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1000)
 
     # clear messages
     TestUtils.flush()
@@ -63,8 +63,8 @@ defmodule Cachex.Actions.PersistTest do
     {cache, _nodes, _cluster} = TestUtils.create_cache_cluster(2)
 
     # we know that 1 & 2 hash to different nodes
-    {:ok, true} = Cachex.put(cache, 1, 1, ttl: 5000)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 5000)
+    {:ok, true} = Cachex.put(cache, 1, 1, expire: 5000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 5000)
 
     # remove expirations on both keys
     {:ok, true} = Cachex.persist(cache, 1)
diff --git a/test/cachex/actions/purge_test.exs b/test/cachex/actions/purge_test.exs
index bb4a777..ef22132 100644
--- a/test/cachex/actions/purge_test.exs
+++ b/test/cachex/actions/purge_test.exs
@@ -13,7 +13,7 @@ defmodule Cachex.Actions.PurgeTest do
     cache = TestUtils.create_cache(hooks: [hook])
 
     # add a new cache entry
-    {:ok, true} = Cachex.put(cache, "key", "value", ttl: 25)
+    {:ok, true} = Cachex.put(cache, "key", "value", expire: 25)
 
     # flush messages
     TestUtils.flush()
@@ -57,8 +57,8 @@ defmodule Cachex.Actions.PurgeTest do
     {cache, _nodes, _cluster} = TestUtils.create_cache_cluster(2)
 
     # we know that 1 & 2 hash to different nodes
-    {:ok, true} = Cachex.put(cache, 1, 1, ttl: 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 1, 1, expire: 1)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
 
     # retrieve the cache size, should be 2
     {:ok, 2} = Cachex.size(cache)
diff --git a/test/cachex/actions/put_many_test.exs b/test/cachex/actions/put_many_test.exs
index ebe2263..69cd9fb 100644
--- a/test/cachex/actions/put_many_test.exs
+++ b/test/cachex/actions/put_many_test.exs
@@ -21,9 +21,9 @@ defmodule Cachex.Actions.PutManyTest do
 
     # set some values in the cache
     set1 = Cachex.put_many(cache1, [{1, 1}, {2, 2}])
-    set2 = Cachex.put_many(cache1, [{3, 3}, {4, 4}], ttl: 5000)
+    set2 = Cachex.put_many(cache1, [{3, 3}, {4, 4}], expire: 5000)
     set3 = Cachex.put_many(cache2, [{1, 1}, {2, 2}])
-    set4 = Cachex.put_many(cache2, [{3, 3}, {4, 4}], ttl: 5000)
+    set4 = Cachex.put_many(cache2, [{3, 3}, {4, 4}], expire: 5000)
 
     # ensure all set actions worked
     assert(set1 == {:ok, true})
@@ -34,8 +34,8 @@ defmodule Cachex.Actions.PutManyTest do
     # verify the hooks were updated with the message
     assert_receive({{:put_many, [[{1, 1}, {2, 2}], []]}, ^set1})
     assert_receive({{:put_many, [[{1, 1}, {2, 2}], []]}, ^set3})
-    assert_receive({{:put_many, [[{3, 3}, {4, 4}], [ttl: 5000]]}, ^set2})
-    assert_receive({{:put_many, [[{3, 3}, {4, 4}], [ttl: 5000]]}, ^set4})
+    assert_receive({{:put_many, [[{3, 3}, {4, 4}], [expire: 5000]]}, ^set2})
+    assert_receive({{:put_many, [[{3, 3}, {4, 4}], [expire: 5000]]}, ^set4})
 
     # read back all values from the cache
     value1 = Cachex.get(cache1, 1)
diff --git a/test/cachex/actions/put_test.exs b/test/cachex/actions/put_test.exs
index ea66ebd..e9fd6e7 100644
--- a/test/cachex/actions/put_test.exs
+++ b/test/cachex/actions/put_test.exs
@@ -21,9 +21,9 @@ defmodule Cachex.Actions.PutTest do
 
     # set some values in the cache
     set1 = Cachex.put(cache1, 1, 1)
-    set2 = Cachex.put(cache1, 2, 2, ttl: 5000)
+    set2 = Cachex.put(cache1, 2, 2, expire: 5000)
     set3 = Cachex.put(cache2, 1, 1)
-    set4 = Cachex.put(cache2, 2, 2, ttl: 5000)
+    set4 = Cachex.put(cache2, 2, 2, expire: 5000)
 
     # ensure all set actions worked
     assert(set1 == {:ok, true})
@@ -34,8 +34,8 @@ defmodule Cachex.Actions.PutTest do
     # verify the hooks were updated with the message
     assert_receive({{:put, [1, 1, []]}, ^set1})
     assert_receive({{:put, [1, 1, []]}, ^set3})
-    assert_receive({{:put, [2, 2, [ttl: 5000]]}, ^set2})
-    assert_receive({{:put, [2, 2, [ttl: 5000]]}, ^set4})
+    assert_receive({{:put, [2, 2, [expire: 5000]]}, ^set2})
+    assert_receive({{:put, [2, 2, [expire: 5000]]}, ^set4})
 
     # read back all values from the cache
     value1 = Cachex.get(cache1, 1)
diff --git a/test/cachex/actions/refresh_test.exs b/test/cachex/actions/refresh_test.exs
index 367c162..6527ec0 100644
--- a/test/cachex/actions/refresh_test.exs
+++ b/test/cachex/actions/refresh_test.exs
@@ -14,7 +14,7 @@ defmodule Cachex.Actions.RefreshTest do
 
     # add some keys to the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1000)
 
     # clear messages
     TestUtils.flush()
@@ -69,8 +69,8 @@ defmodule Cachex.Actions.RefreshTest do
     {cache, _nodes, _cluster} = TestUtils.create_cache_cluster(2)
 
     # we know that 1 & 2 hash to different nodes
-    {:ok, true} = Cachex.put(cache, 1, 1, ttl: 500)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 500)
+    {:ok, true} = Cachex.put(cache, 1, 1, expire: 500)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 500)
 
     # pause to reduce the TTL a little
     :timer.sleep(250)
diff --git a/test/cachex/actions/size_test.exs b/test/cachex/actions/size_test.exs
index 92b1760..245820a 100644
--- a/test/cachex/actions/size_test.exs
+++ b/test/cachex/actions/size_test.exs
@@ -34,7 +34,7 @@ defmodule Cachex.Actions.SizeTest do
     assert_receive({{:size, [[]]}, ^result2})
 
     # add a final entry
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
 
     # let it expire
     :timer.sleep(2)
diff --git a/test/cachex/actions/stream_test.exs b/test/cachex/actions/stream_test.exs
index 2bfabd8..bc56106 100644
--- a/test/cachex/actions/stream_test.exs
+++ b/test/cachex/actions/stream_test.exs
@@ -40,9 +40,12 @@ defmodule Cachex.Actions.StreamTest do
     {:ok, true} = Cachex.put(cache, "key2", "value2")
     {:ok, true} = Cachex.put(cache, "key3", "value3")
 
+    # create our query filter
+    filter = Cachex.Query.unexpired()
+
     # create two test queries
-    query1 = Cachex.Query.where(true, {:key, :value})
-    query2 = Cachex.Query.where(true, :key)
+    query1 = Cachex.Query.create(where: filter, output: {:key, :value})
+    query2 = Cachex.Query.create(where: filter, output: :key)
 
     # create cache streams
     {:ok, stream1} = Cachex.stream(cache, query1)
diff --git a/test/cachex/actions/take_test.exs b/test/cachex/actions/take_test.exs
index 3f5256a..2c7249e 100644
--- a/test/cachex/actions/take_test.exs
+++ b/test/cachex/actions/take_test.exs
@@ -13,7 +13,7 @@ defmodule Cachex.Actions.TakeTest do
 
     # set some keys in the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
 
     # wait for the TTL to pass
     :timer.sleep(2)
diff --git a/test/cachex/actions/touch_test.exs b/test/cachex/actions/touch_test.exs
index 457e6f2..943cbe5 100644
--- a/test/cachex/actions/touch_test.exs
+++ b/test/cachex/actions/touch_test.exs
@@ -17,20 +17,23 @@ defmodule Cachex.Actions.TouchTest do
 
     # add some keys to the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1000)
 
     # clear messages
     TestUtils.flush()
 
     # retrieve the raw records
-    entry(touched: touched1, ttl: ttl1) = Cachex.Actions.read(state, 1)
-    entry(touched: touched2, ttl: ttl2) = Cachex.Actions.read(state, 2)
+    entry(modified: modified1, expiration: expiration1) =
+      Cachex.Actions.read(state, 1)
+
+    entry(modified: modified2, expiration: expiration2) =
+      Cachex.Actions.read(state, 2)
 
     # the first TTL should be nil
-    assert(ttl1 == nil)
+    assert(expiration1 == nil)
 
     # the second TTL should be roughly 1000
-    assert_in_delta(ttl2, 995, 6)
+    assert_in_delta(expiration2, 995, 6)
 
     # wait for 50ms
     :timer.sleep(50)
@@ -53,26 +56,29 @@ defmodule Cachex.Actions.TouchTest do
     assert_receive({{:touch, [3, []]}, ^touch3})
 
     # retrieve the raw records again
-    entry(touched: touched3, ttl: ttl3) = Cachex.Actions.read(state, 1)
-    entry(touched: touched4, ttl: ttl4) = Cachex.Actions.read(state, 2)
+    entry(modified: modified3, expiration: expiration3) =
+      Cachex.Actions.read(state, 1)
+
+    entry(modified: modified4, expiration: expiration4) =
+      Cachex.Actions.read(state, 2)
 
-    # the first ttl should still be nil
-    assert(ttl3 == nil)
+    # the first expiration should still be nil
+    assert(expiration3 == nil)
 
     # the first touch time should be roughly 50ms after the first one
-    assert_in_delta(touched3, touched1 + 60, 11)
+    assert_in_delta(modified3, modified1 + 60, 11)
 
-    # the second ttl should be roughly 50ms lower than the first
-    assert_in_delta(ttl4, ttl2 - 60, 11)
+    # the second expiration should be roughly 50ms lower than the first
+    assert_in_delta(expiration4, expiration2 - 60, 11)
 
     # the second touch time should also be 50ms after the first one
-    assert_in_delta(touched4, touched2 + 60, 11)
+    assert_in_delta(modified4, modified2 + 60, 11)
 
-    # for good measure, retrieve the second ttl
-    ttl5 = Cachex.ttl!(cache, 2)
+    # for good measure, retrieve the second expiration
+    expiration5 = Cachex.ttl!(cache, 2)
 
     # it should be roughly 945ms left
-    assert_in_delta(ttl5, 940, 11)
+    assert_in_delta(expiration5, 940, 11)
   end
 
   # This test verifies that this action is correctly distributed across
@@ -97,8 +103,8 @@ defmodule Cachex.Actions.TouchTest do
     [record1, record2] = Enum.sort(export1)
 
     # unpack the records touch time
-    entry(touched: touched1) = record1
-    entry(touched: touched2) = record2
+    entry(modified: modified1) = record1
+    entry(modified: modified2) = record2
 
     # now touch both keys
     {:ok, true} = Cachex.touch(cache, 1)
@@ -111,11 +117,11 @@ defmodule Cachex.Actions.TouchTest do
     [record3, record4] = Enum.sort(export2)
 
     # unpack the records touch time
-    entry(touched: touched3) = record3
-    entry(touched: touched4) = record4
+    entry(modified: modified3) = record3
+    entry(modified: modified4) = record4
 
-    # new touched should be larger than old
-    assert(touched3 > touched1)
-    assert(touched4 > touched2)
+    # new modified should be larger than old
+    assert(modified3 > modified1)
+    assert(modified4 > modified2)
   end
 end
diff --git a/test/cachex/actions/ttl_test.exs b/test/cachex/actions/ttl_test.exs
index d3ec866..365be52 100644
--- a/test/cachex/actions/ttl_test.exs
+++ b/test/cachex/actions/ttl_test.exs
@@ -10,7 +10,7 @@ defmodule Cachex.Actions.TtlTest do
 
     # set several keys in the cache
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 10000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 10000)
 
     # verify the TTL of both keys
     ttl1 = Cachex.ttl(cache, 1)
@@ -38,8 +38,8 @@ defmodule Cachex.Actions.TtlTest do
     {cache, _nodes, _cluster} = TestUtils.create_cache_cluster(2)
 
     # we know that 1 & 2 hash to different nodes
-    {:ok, true} = Cachex.put(cache, 1, 1, ttl: 500)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 500)
+    {:ok, true} = Cachex.put(cache, 1, 1, expire: 500)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 500)
 
     # check the expiration of each key in the cluster
     {:ok, expiration1} = Cachex.ttl(cache, 1)
diff --git a/test/cachex/actions/update_test.exs b/test/cachex/actions/update_test.exs
index d5e76b3..8cc2c3a 100644
--- a/test/cachex/actions/update_test.exs
+++ b/test/cachex/actions/update_test.exs
@@ -13,7 +13,7 @@ defmodule Cachex.Actions.UpdateTest do
     {:ok, true} = Cachex.put(cache, 1, 1)
 
     # set a value with a TTL in the cache
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 10000)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 10000)
 
     # attempt to update both keys
     update1 = Cachex.update(cache, 1, 3)
@@ -66,8 +66,8 @@ defmodule Cachex.Actions.UpdateTest do
     {cache, _nodes, _cluster} = TestUtils.create_cache_cluster(2)
 
     # we know that 1 & 2 hash to different nodes
-    {:ok, true} = Cachex.put(cache, 1, 1, ttl: 500)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 500)
+    {:ok, true} = Cachex.put(cache, 1, 1, expire: 500)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 500)
 
     # run updates against both keys
     {:ok, true} = Cachex.update(cache, 1, -1)
diff --git a/test/cachex/actions_test.exs b/test/cachex/actions_test.exs
index 21e023e..2658266 100644
--- a/test/cachex/actions_test.exs
+++ b/test/cachex/actions_test.exs
@@ -25,7 +25,7 @@ defmodule Cachex.ActionsTest do
 
     # write several values
     {:ok, true} = Cachex.put(cache, 1, 1)
-    {:ok, true} = Cachex.put(cache, 2, 2, ttl: 1)
+    {:ok, true} = Cachex.put(cache, 2, 2, expire: 1)
 
     # let the TTL expire
     :timer.sleep(2)
@@ -36,7 +36,7 @@ defmodule Cachex.ActionsTest do
     record3 = Cachex.Actions.read(state, 3)
 
     # the first should find a record
-    assert(match?({:entry, 1, _touched, nil, 1}, record1))
+    assert(match?(entry(key: 1, value: 1), record1))
 
     # the second should expire
     assert(record2 == nil)
@@ -67,8 +67,8 @@ defmodule Cachex.ActionsTest do
         state,
         entry(
           key: "key",
-          touched: 1,
-          value: "value"
+          value: "value",
+          modified: 1
         )
       )
 
@@ -83,8 +83,8 @@ defmodule Cachex.ActionsTest do
       value1 ==
         entry(
           key: "key",
-          touched: 1,
-          value: "value"
+          value: "value",
+          modified: 1
         )
     )
 
@@ -106,8 +106,8 @@ defmodule Cachex.ActionsTest do
       value2 ==
         entry(
           key: "key",
-          touched: 1,
-          value: "yek"
+          value: "yek",
+          modified: 1
         )
     )
   end
diff --git a/test/cachex/options_test.exs b/test/cachex/options_test.exs
index ff9002c..7f92569 100644
--- a/test/cachex/options_test.exs
+++ b/test/cachex/options_test.exs
@@ -34,12 +34,14 @@ defmodule Cachex.OptionsTest do
 
     # parse out using a true condition
     result1 = Cachex.Options.get(options, :positive, condition)
+    result2 = Cachex.Options.get(options, [:positive, :negative], condition)
 
     # parse out using a false condition (should return a default)
-    result2 = Cachex.Options.get(options, :negative, condition)
+    result3 = Cachex.Options.get(options, :negative, condition)
+    result4 = Cachex.Options.get(options, [:negative, :negative], condition)
 
     # parse out using an error condition (should return a custom default)
-    result3 =
+    result5 =
       Cachex.Options.get(
         options,
         :negative,
@@ -51,12 +53,14 @@ defmodule Cachex.OptionsTest do
 
     # condition true means we return the value
     assert(result1 == 10)
+    assert(result2 == 10)
 
     # condition false and no default means we return nil
-    assert(result2 == nil)
+    assert(result3 == nil)
+    assert(result4 == nil)
 
     # condition false with a default returns the default
-    assert(result3 == 0)
+    assert(result5 == 0)
   end
 
   # This test makes sure that we can correctly parse out commands which are to
@@ -135,8 +139,7 @@ defmodule Cachex.OptionsTest do
     refute comp3
   end
 
-  # This test verifies the parsing of TTL related flags. We have to test various
-  # combinations of :ttl_interval and :default_ttl to verify each state correctly.
+  # This test verifies the parsing of TTL related flags.
   test "parsing :expiration flags" do
     # grab a cache name
     name = TestUtils.create_name()
diff --git a/test/cachex/policy/lrw/evented_test.exs b/test/cachex/policy/lrw/evented_test.exs
index 0a86b8d..5c53648 100644
--- a/test/cachex/policy/lrw/evented_test.exs
+++ b/test/cachex/policy/lrw/evented_test.exs
@@ -147,7 +147,7 @@ defmodule Cachex.Policy.LRW.EventedTest do
     # set a more recent 50 keys
     for x <- 51..100 do
       # set the key
-      {:ok, true} = Cachex.put(state, x, x, ttl: 1)
+      {:ok, true} = Cachex.put(state, x, x, expire: 1)
 
       # tick to make sure each has a new touch time
       :timer.sleep(1)
diff --git a/test/cachex/policy/lrw/scheduled_test.exs b/test/cachex/policy/lrw/scheduled_test.exs
index 41f216e..5db0c92 100644
--- a/test/cachex/policy/lrw/scheduled_test.exs
+++ b/test/cachex/policy/lrw/scheduled_test.exs
@@ -135,7 +135,7 @@ defmodule Cachex.Policy.LRW.ScheduledTest do
     # set a more recent 50 keys
     for x <- 51..100 do
       # set the key
-      {:ok, true} = Cachex.put(state, x, x, ttl: 1)
+      {:ok, true} = Cachex.put(state, x, x, expire: 1)
 
       # tick to make sure each has a new touch time
       :timer.sleep(1)
diff --git a/test/cachex/query_test.exs b/test/cachex/query_test.exs
index ce30ee2..b4b30e3 100644
--- a/test/cachex/query_test.exs
+++ b/test/cachex/query_test.exs
@@ -1,95 +1,86 @@
 defmodule Cachex.QueryTest do
   use Cachex.Test.Case
 
-  # All queries are run through the basic query generation, so this test
-  # will just validate the passing of query clauses through to the query
-  # creation default, which will attach the checks for expirations.
   test "creating basic queries" do
-    # create a query with a true filter
-    query1 = Cachex.Query.where(true)
-    query2 = Cachex.Query.where(true, :key)
+    # create a query with not filter
+    query1 = Cachex.Query.create()
+    query2 = Cachex.Query.create(output: :key)
 
     # verify the mapping of both queries
     assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query1
     assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query2
 
     # unpack clauses of both queries
-    [{_, [{:andalso, c1, true}], _}] = query1
-    [{_, [{:andalso, c2, true}], _}] = query2
-
-    # verify the queries of both queries
-    assert {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, _now}} = c1
-    assert {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, _now}} = c2
+    [{_, [true], _}] = query1
+    [{_, [true], _}] = query2
 
     # verify the returns of both queries
     assert [{_, _, [:"$_"]}] = query1
     assert [{_, _, [:"$1"]}] = query2
   end
 
-  # The `expired()` function is just a wrapper to `where` whilst inverting
-  # the expiration checks. This test just covers this behaviour.
   test "creating expired queries" do
+    # create base expired filter
+    filter1 = Cachex.Query.expired()
+    filter2 = Cachex.Query.expired(false)
+
     # create a couple of expired queries
-    query1 = Cachex.Query.expired()
-    query2 = Cachex.Query.expired(:key)
+    clause1 = Cachex.Query.create(where: filter1)
+    clause2 = Cachex.Query.create(where: filter1, output: :key)
+    clause3 = Cachex.Query.create(where: filter2)
 
     # verify the mapping of both queries
-    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query1
-    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query2
+    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = clause1
+    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = clause2
+    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = clause3
 
     # unpack clauses of both queries
-    [{_, [{:not, c1}], _}] = query1
-    [{_, [{:not, c2}], _}] = query2
+    [{_, [{:not, c1}], _}] = clause1
+    [{_, [{:not, c2}], _}] = clause2
+    [{_, [{:andalso, {:not, c3}, false}], _}] = clause3
 
     # verify the queries of both queries
-    assert {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, _now}} = c1
-    assert {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, _now}} = c2
+    assert {:orelse, {:==, :"$4", nil}, {:>, {:+, :"$3", :"$4"}, _now}} = c1
+    assert {:orelse, {:==, :"$4", nil}, {:>, {:+, :"$3", :"$4"}, _now}} = c2
+    assert {:orelse, {:==, :"$4", nil}, {:>, {:+, :"$3", :"$4"}, _now}} = c3
 
     # verify the returns of both queries
-    assert [{_, _, [:"$_"]}] = query1
-    assert [{_, _, [:"$1"]}] = query2
+    assert [{_, _, [:"$_"]}] = clause1
+    assert [{_, _, [:"$1"]}] = clause2
+    assert [{_, _, [:"$_"]}] = clause3
   end
 
-  # The `unexpired()` function is just a wrapper to `create` whilst without a
-  # secondary clause. This test just covers this behaviour.
   test "creating unexpired queries" do
+    # create base unexpired filter
+    filter1 = Cachex.Query.unexpired()
+    filter2 = Cachex.Query.unexpired(false)
+
     # create a couple of unexpired queries
-    query1 = Cachex.Query.unexpired()
-    query2 = Cachex.Query.unexpired(:key)
+    clause1 = Cachex.Query.create(where: filter1)
+    clause2 = Cachex.Query.create(where: filter1, output: :key)
+    clause3 = Cachex.Query.create(where: filter2)
 
     # verify the mapping of both queries
-    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query1
-    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query2
+    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = clause1
+    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = clause2
+    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = clause3
 
     # unpack clauses of both queries
-    [{_, [c1], _}] = query1
-    [{_, [c2], _}] = query2
-
-    # verify the queries of both queries
-    assert {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, _now}} = c1
-    assert {:orelse, {:==, :"$3", nil}, {:>, {:+, :"$2", :"$3"}, _now}} = c2
+    [{_, [c1], _}] = clause1
+    [{_, [c2], _}] = clause2
+    [{_, [c3], _}] = clause3
 
-    # verify the returns of both queries
-    assert [{_, _, [:"$_"]}] = query1
-    assert [{_, _, [:"$1"]}] = query2
-  end
+    # verify the queries of all queries
+    assert {:orelse, {:==, :"$4", nil}, {:>, {:+, :"$3", :"$4"}, _now}} = c1
+    assert {:orelse, {:==, :"$4", nil}, {:>, {:+, :"$3", :"$4"}, _now}} = c2
 
-  # This test just covers the default value checking when creating raw
-  # queries with none of the provided bindings. This does nothing more
-  # than validate structure, as there are no attached conditions added.
-  test "creating raw queries" do
-    # create a query with a true filter
-    query1 = Cachex.Query.raw(true)
-    query2 = Cachex.Query.raw(true, :key)
+    assert {:andalso,
+            {:orelse, {:==, :"$4", nil}, {:>, {:+, :"$3", :"$4"}, _now}},
+            false} = c3
 
-    # verify the form of the first query
-    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query1
-    assert [{_, [true], _}] = query1
-    assert [{_, _, [:"$_"]}] = query1
-
-    # verify the form of the second query
-    assert [{{:_, :"$1", :"$2", :"$3", :"$4"}, _, _}] = query2
-    assert [{_, [true], _}] = query2
-    assert [{_, _, [:"$1"]}] = query2
+    # verify the returns of both queries
+    assert [{_, _, [:"$_"]}] = clause1
+    assert [{_, _, [:"$1"]}] = clause2
+    assert [{_, _, [:"$_"]}] = clause3
   end
 end
diff --git a/test/cachex/services/courier_test.exs b/test/cachex/services/courier_test.exs
index 8e797a7..405b021 100644
--- a/test/cachex/services/courier_test.exs
+++ b/test/cachex/services/courier_test.exs
@@ -29,7 +29,7 @@ defmodule Cachex.Services.CourierTest do
     # define our task function
     task = fn ->
       :timer.sleep(250)
-      {:commit, "my_value", ttl: :timer.seconds(60)}
+      {:commit, "my_value", expire: :timer.seconds(60)}
     end
 
     # start a new cache
@@ -46,7 +46,7 @@ defmodule Cachex.Services.CourierTest do
     result = Services.Courier.dispatch(cache, "my_key", task)
 
     # check the returned value with the options set
-    assert result == {:commit, "my_value", [ttl: 60000]}
+    assert result == {:commit, "my_value", [expire: 60000]}
 
     # check the forwarded task completed (no options)
     assert_receive({:ok, "my_value"})
diff --git a/test/cachex/services/janitor_test.exs b/test/cachex/services/janitor_test.exs
index c24a048..b7ae834 100644
--- a/test/cachex/services/janitor_test.exs
+++ b/test/cachex/services/janitor_test.exs
@@ -8,30 +8,42 @@ defmodule Cachex.Services.JanitorTest do
   # it disabled, it should return false regardless of the date deltas.
   test "checking whether an expiration has passed" do
     # this combination has expired
-    touched1 = 5000
-    time_tl1 = 5000
+    modified1 = 5000
+    expiration1 = 5000
 
     # this combination has not
-    touched2 = :os.system_time(:milli_seconds)
-    time_tl2 = 100_000_000
+    modified2 = :os.system_time(:milli_seconds)
+    expiration2 = 100_000_000
 
     # define both an enabled and disabled state
     state1 = cache(expiration: expiration(lazy: true))
     state2 = cache(expiration: expiration(lazy: false))
 
     # expired combination regardless of state
-    result1 = Services.Janitor.expired?(entry(touched: touched1, ttl: time_tl1))
+    result1 =
+      Services.Janitor.expired?(
+        entry(modified: modified1, expiration: expiration1)
+      )
 
     # unexpired combination regardless of state
-    result2 = Services.Janitor.expired?(entry(touched: touched2, ttl: time_tl2))
+    result2 =
+      Services.Janitor.expired?(
+        entry(modified: modified2, expiration: expiration2)
+      )
 
     # expired combination with state enabled
     result3 =
-      Services.Janitor.expired?(state1, entry(touched: touched1, ttl: time_tl1))
+      Services.Janitor.expired?(
+        state1,
+        entry(modified: modified1, expiration: expiration1)
+      )
 
     # expired combination with state disabled
     result4 =
-      Services.Janitor.expired?(state2, entry(touched: touched1, ttl: time_tl1))
+      Services.Janitor.expired?(
+        state2,
+        entry(modified: modified1, expiration: expiration1)
+      )
 
     # only the first and third should have expired
     assert(result1)
@@ -66,7 +78,7 @@ defmodule Cachex.Services.JanitorTest do
     cache = Services.Overseer.retrieve(cache)
 
     # add a new cache entry
-    {:ok, true} = Cachex.put(cache, "key", "value", ttl: ttl_value)
+    {:ok, true} = Cachex.put(cache, "key", "value", expire: ttl_value)
 
     # check that the key exists
     exists1 = Cachex.exists?(cache, "key")
diff --git a/test/cachex/spec/validator_test.exs b/test/cachex/spec/validator_test.exs
index fd6f257..be235d9 100644
--- a/test/cachex/spec/validator_test.exs
+++ b/test/cachex/spec/validator_test.exs
@@ -42,10 +42,10 @@ defmodule Cachex.Spec.ValidatorTest do
 
   test "validation of entry records" do
     # define some valid records
-    entry1 = entry(key: "key", touched: 1, ttl: nil, value: "value")
-    entry2 = entry(key: "key", touched: 1, ttl: 1, value: "value")
-    entry3 = entry(key: "key", touched: 1, ttl: nil, value: nil)
-    entry4 = entry(key: nil, touched: 1, ttl: nil, value: nil)
+    entry1 = entry(key: "key", modified: 1, value: "value")
+    entry2 = entry(key: "key", modified: 1, expiration: 1, value: "value")
+    entry3 = entry(key: "key", modified: 1)
+    entry4 = entry(key: nil, modified: 1)
 
     # ensure all records are valid
     assert Validator.valid?(:entry, entry1)
@@ -54,11 +54,11 @@ defmodule Cachex.Spec.ValidatorTest do
     assert Validator.valid?(:entry, entry4)
 
     # define some invalid records
-    entry5 = entry(key: "key", touched: nil, ttl: nil, value: nil)
-    entry6 = entry(key: "key", touched: " ", ttl: nil, value: nil)
-    entry7 = entry(key: "key", touched: -1, ttl: nil, value: nil)
-    entry8 = entry(key: "key", touched: 1, ttl: " ", value: nil)
-    entry9 = entry(key: "key", touched: 1, ttl: -1, value: nil)
+    entry5 = entry(key: "key", modified: nil)
+    entry6 = entry(key: "key", modified: " ")
+    entry7 = entry(key: "key", modified: -1)
+    entry8 = entry(key: "key", modified: 1, expiration: " ")
+    entry9 = entry(key: "key", modified: 1, expiration: -1)
 
     # ensure all records are invalid
     refute Validator.valid?(:entry, entry5)
diff --git a/test/cachex/spec_test.exs b/test/cachex/spec_test.exs
index b6b5c0c..b35b386 100644
--- a/test/cachex/spec_test.exs
+++ b/test/cachex/spec_test.exs
@@ -42,28 +42,32 @@ defmodule Cachex.SpecTest do
 
   test "generating entry index locations" do
     assert entry_idx(:key) == 2
-    assert entry_idx(:touched) == 3
-    assert entry_idx(:ttl) == 4
-    assert entry_idx(:value) == 5
+    assert entry_idx(:value) == 3
+    assert entry_idx(:modified) == 4
+    assert entry_idx(:expiration) == 5
   end
 
   test "generating entry modifications" do
-    assert entry_mod({:key, "key"}) == {2, "key"}
-    assert entry_mod(key: "key", value: "value") == [{2, "key"}, {5, "value"}]
+    assert entry_mod({:key, "key"}) == {entry_idx(:key), "key"}
+
+    assert entry_mod(key: "key", value: "value") == [
+             {entry_idx(:key), "key"},
+             {entry_idx(:value), "value"}
+           ]
   end
 
   test "generating entry modifications with a touch time update" do
-    assert [{3, _now}] = entry_mod_now()
-    assert [{3, _now}, {2, "key"}] = entry_mod_now(key: "key")
+    assert [{4, _now}] = entry_mod_now()
+    assert [{4, _now}, {2, "key"}] = entry_mod_now(key: "key")
   end
 
   test "generating entries based on the current time" do
-    entry(touched: touched1) = entry_now()
-    entry(touched: touched2, key: key) = entry_now(key: "key")
+    entry(modified: modified1) = entry_now()
+    entry(modified: modified2, key: key) = entry_now(key: "key")
 
     assert key == "key"
-    assert_in_delta(touched1, :os.system_time(1000), 5)
-    assert_in_delta(touched2, :os.system_time(1000), 5)
+    assert_in_delta(modified1, :os.system_time(1000), 5)
+    assert_in_delta(modified2, :os.system_time(1000), 5)
   end
 
   test "name generation for components" do
diff --git a/test/cachex/stats_test.exs b/test/cachex/stats_test.exs
index 461c853..fcf10f7 100644
--- a/test/cachex/stats_test.exs
+++ b/test/cachex/stats_test.exs
@@ -269,7 +269,7 @@ defmodule Cachex.StatsTest do
 
     # set a few values in the cache
     for i <- 0..4 do
-      {:ok, true} = Cachex.put(cache, i, i, ttl: 1)
+      {:ok, true} = Cachex.put(cache, i, i, expire: 1)
     end
 
     # ensure purge
diff --git a/test/cachex/warmer_test.exs b/test/cachex/warmer_test.exs
index 6c5429a..88027f1 100644
--- a/test/cachex/warmer_test.exs
+++ b/test/cachex/warmer_test.exs
@@ -17,7 +17,7 @@ defmodule Cachex.WarmerTest do
   test "warmers which set values with options" do
     # create a test warmer to pass to the cache
     TestUtils.create_warmer(:options_warmer, 50, fn _ ->
-      {:ok, [{1, 1}], [ttl: 60000]}
+      {:ok, [{1, 1}], [expire: 60000]}
     end)
 
     # create a cache instance with a warmer