   # Encodes an instance of `type`. Returns an iodata instead of a binary.
   # Made public for testing.
   @doc false
-  def encode_type(data, type)
-
-  def encode_type(str, :string) do
+  def encode_type(data, type, offset \\ nil)
+
+  def encode_type(str, :string, _) when is_binary(str) do
     [:small_ints.encode_zigzag_varint(byte_size(str)), str]
   end
 
-  def encode_type(i, type) when type in [:sint16, :sint32, :sint64] do
+  def encode_type(i, type, _) when type in [:sint16, :sint32, :sint64] and is_integer(i) do
     :small_ints.encode_zigzag_varint(i)
   end
 
-  defp field_name(field) when is_record(field, :named_field), do: named_field(field, :name)
+  def encode_type(map, :embedded_map, offset) when is_map(map) do
+    offset = offset + map_header_offset(map)
+
+    {keys, values, _} = Enum.reduce map, {[], [], offset}, fn({key, value}, {ks, vs, index}) ->
+      typed_field(value: value, type: type) = value
+      encoded_value = encode_type(value, type)
+      key = [type_to_int(:string), encode_type(key, :string), <<index :: 32-signed>>, type_to_int(type)]
+      index = index + IO.iodata_length(encoded_value)
+      {[key|ks], [encoded_value|vs], index}
+    end
+
+    nkeys = map |> Map.keys |> Enum.count |> :small_ints.encode_zigzag_varint
+
+    [nkeys, keys, values]
+  end
+
+  defp map_header_offset(map) do
+    keys = Map.keys(map)
+
+    # `6` means 4 bytes for the pointer to the data, 1 byte for the data type,
+    # and 1 byte for the key type.
+    nkeys       = :small_ints.encode_zigzag_varint(Enum.count(keys))
+    key_lengths = Enum.map(keys, &(IO.iodata_length(encode_type(&1, :string)) + 6))
+
+    byte_size(nkeys) + Enum.sum(key_lengths)
+  end
 
   # http://orientdb.com/docs/last/Types.html
   @types [


  # Returns the given `%Field{}` with the `:encoded_value` field set to the
  # result of encoding the `:value` field.
  defp encode_field_value(%Field{type: type, value: value} = field) do
    %{field | encoded_value: encode_type(value, type)}
  end

  # Encodes the given `%Field{}` for the header, i.e., just the field

    end
  end

  defp decode_type(data, :embedded_map) do
    {keys, rest}   = decode_map_header(data)
    {keys_and_values, rest} = decode_map_values(rest, keys)

    {Enum.into(keys_and_values, %{}), rest}
  end

  defp decode_map_header(data) do
    {nkeys, rest} = :small_ints.decode_zigzag_varint(data)

    {keys, rest} = Enum.map_reduce List.duplicate(0, nkeys), rest, fn(_, <<string_type, acc :: binary>>) ->
      # For now, OrientDB only supports STRING keys.
      :string = int_to_type(string_type)

      {key, acc} = decode_type(acc, :string)
      {ptr, acc} = decode_data_ptr(acc)
      IO.inspect ptr
      <<type, acc :: binary>> = acc

      {map_key(key: key, data_type: int_to_type(type), data_ptr: ptr), acc}
    end
  end

  defp decode_map_values(data, keys) do
    Enum.map_reduce keys, data, fn(map_key(key: key_name, data_type: type, data_ptr: ptr), acc) ->
      if ptr == 0 do
        {{key_name, nil}, acc}
      else
