The \hyperlink{doc_tutorials_plugins_md}{plugin tutorial} already covers some of the most interesting parts on how to write a (storage) plugin. This text will tell you a little bit more about how a storage plugin should act. While it is usually relatively easy to create a plugin that stores basic key-\/value pairs, adding advanced features such as support for


\begin{DoxyItemize}
\item \hyperlink{doc_tutorials_arrays_md}{arrays}, and
\item \hyperlink{doc_dev_metadata_md}{metadata},
\end{DoxyItemize}

takes more work. Before you continue with this text, please make sure that you read all of the linked documents above.

\subsection*{Don’t Add Additional Keys}

One common problem of storage plugins is, that they store too many keys. For example, if the user adds the keys


\begin{DoxyItemize}
\item {\ttfamily user/tests/storage/root} and
\item {\ttfamily user/tests/storage/root/level1/level2/level3},
\end{DoxyItemize}

then your plugin should only store those two keys. {\bfseries Do not} add the keys


\begin{DoxyItemize}
\item {\ttfamily user/tests/storage/root/level1}, or
\item {\ttfamily user/tests/storage/root/level1/level2}
\end{DoxyItemize}

to the key set. One plugin that handles this situation properly is \hyperlink{md_src_plugins_yamlcpp_README_src_plugins_yamlcpp_README_md}{Y\+A\+ML C\+PP}, as the following \href{https://master.libelektra.org/tests/shell/shell_recorder/tutorial_wrapper}{\tt Markdown Shell Recorder} test shows\+:


\begin{DoxyCode}
# Mount plugin
sudo kdb mount config.yaml user/tests/storage yamlcpp

# Add key-value pairs
kdb set user/tests/storage/root 🐓
kdb set user/tests/storage/root/level1/level2/level3 🐣

# Make sure that YAML CPP did not store any additional keys
kdb ls user/tests/storage/root
#> user/tests/storage/root
#> user/tests/storage/root/level1/level2/level3

# Undo modifications to the key database
kdb rm -r user/tests/storage
sudo kdb umount user/tests/storage
\end{DoxyCode}


. For more information on why we allow “holes” in the hierarchy, please take a look \hyperlink{doc_decisions_holes_md}{here}.

\subsection*{Differentiate Between Empty Keys and Keys Containing an Empty String}

Elektra supports both binary and textual values. The main difference between binary and textual data is that textual data always ends with a null byte. Therefore you are not allowed to store the code point {\ttfamily 0} inside textual data. Binary data does not have this limitation.

The simplest textual data is the empty string ({\ttfamily \char`\"{}\char`\"{}} = {\ttfamily 0}) and has length 1, while the simplest binary data stores nothing at all and therefore has length 0. In the {\ttfamily kdb} utility you can disambiguate between these value by checking for the \hyperlink{doc_help_elektra-metadata_md}{metakey `binary`}. The following \href{https://master.libelektra.org/tests/shell/shell_recorder/tutorial_wrapper}{\tt Markdown Shell Recorder} test shows how a storage plugin should handle these values.


\begin{DoxyCode}
# Mount plugin
sudo kdb mount config.yaml user/tests/storage yamlcpp

kdb set user/tests/storage/null
#> Create a new key user/tests/storage/null with null value
kdb get user/tests/storage/null
#>
kdb lsmeta user/tests/storage/null
#> binary

kdb set user/tests/storage/empty ''
#> Create a new key user/tests/storage/empty with string ""
kdb get user/tests/storage/empty
#>
kdb lsmeta user/tests/storage/empty
#>

# Undo modifications to the key database
kdb rm -r user/tests/storage
sudo kdb umount user/tests/storage
\end{DoxyCode}


\subsection*{Convert Boolean Data}

Elektra uses \hyperlink{doc_decisions_bool_md}{`0` and `1` to represent binary data}. A storage plugin that uses other values (e.\+g. {\ttfamily false} and {\ttfamily true}) needs to convert these values to {\ttfamily 0} and {\ttfamily 1}. The \href{https://master.libelektra.org/tests/shell/shell_recorder/tutorial_wrapper}{\tt Markdown Shell Recorder} test below shows that \hyperlink{md_src_plugins_yamlcpp_README_src_plugins_yamlcpp_README_md}{Y\+A\+ML C\+PP} handles the conversion from and to \href{https://yaml.org/spec/1.2/spec.html#id2803629}{\tt Y\+A\+M\+L’s boolean type} properly. In the test we also use the \hyperlink{md_src_plugins_type_README_src_plugins_type_README_md}{`type` plugin} to makes sure that Y\+A\+ML C\+PP interacts correctly with this essential plugin.


\begin{DoxyCode}
# Mount plugin
kdb mount config.yaml user/tests/storage yamlcpp type
kdb set user/tests/storage/bool/value true
kdb get user/tests/storage/bool/value
#> 1

kdb setmeta user/tests/storage/bool/value type boolean
kdb set user/tests/storage/bool/value 1
kdb get user/tests/storage/bool/value
#> 1

kdb set user/tests/storage/bool/value false
kdb get user/tests/storage/bool/value
#> 0

kdb set user/tests/storage/bool/value 'non boolean'
# RET: 5

kdb get user/tests/storage/bool/value
#> 0

# Undo modifications to the key database
kdb rm -r user/tests/storage
sudo kdb umount user/tests/storage
\end{DoxyCode}


\subsection*{Support Values Inside Non-\/\+Leaf Keys}

Sometimes the most “natural” mapping of key-\/value pairs to a file format might cause a storage plugin to not be able to store values in so called directory (non-\/leaf) keys.

For example, in a key set that contains the keys\+:


\begin{DoxyCode}
user/directory
user/directory/leaf1
user/directory/leaf2
user/leaf3
\end{DoxyCode}


, all keys at the bottom of the hierarchy\+:


\begin{DoxyCode}
        user
      /      \(\backslash\)
  directory  leaf3
   /     \(\backslash\)
leaf1   leaf2
\end{DoxyCode}


, such as


\begin{DoxyItemize}
\item {\ttfamily user/directory/leaf1}
\item {\ttfamily user/directory/leaf2}
\item {\ttfamily user/leaf3}
\end{DoxyItemize}

are called leaf keys, while {\ttfamily user/directory} is a directory key. Plugins such as \hyperlink{md_src_plugins_yajl_README_src_plugins_yajl_README_md}{Y\+A\+JL} or \hyperlink{md_src_plugins_yamlcpp_README_src_plugins_yamlcpp_README_md}{Y\+A\+ML C\+PP} will not be able to store data in the key with the name {\ttfamily user/directory} directly. To work around this issue these plugin use the \hyperlink{md_src_plugins_directoryvalue_README_src_plugins_directoryvalue_README_md}{Directory Value plugin}. In the Read\+Me of the \href{https://www.libelektra.org/plugins/directoryvalue}{\tt Directory Value plugin} and \href{https://www.libelektra.org/plugins/yamlcpp}{\tt Y\+A\+ML C\+PP} you will find more information about this issue, and how to handle it.

The following Markdown Shell Recorder test shows {\bfseries the proper behavior}\+:


\begin{DoxyCode}
# Mount plugin
sudo kdb mount config.yaml user/tests/storage yamlcpp

# Add key-value pair (leaf key)
kdb set user/tests/storage/root 🐓
# Since we add a key below `user/tests/storage/root`, the key
# `user/tests/storage/root` turns from a leaf key to a directory key.
kdb set user/tests/storage/root/level1/level2/level3 🐣

# Make sure that the directory key still stores the correct value
kdb get user/tests/storage/root
#> 🐓

# Check the value of the leaf key
kdb get user/tests/storage/root/level1/level2/level3
#> 🐣

# Undo modifications to the key database
kdb rm -r user/tests/storage
sudo kdb umount user/tests/storage
\end{DoxyCode}


. To make sure that your storage plugin works correctly, please just replace {\ttfamily yamlcpp} with the name of your plugin and verify that the test above still works.

\subsection*{Support Array And Non-\/\+Array Data Properly}

You already learned about the array syntax in the \hyperlink{doc_tutorials_arrays_md}{array tutorial}. Now it is time to check, if your storage plugin supports array and non-\/array keys properly. Let us look at an concrete example. In the key set that contains keys with the following names\+:


\begin{DoxyCode}
user/tests/storage/array/#0
user/tests/storage/array/#1
user/tests/storage/map/#0
user/tests/storage/map/key
user/tests/storage/map/#1
\end{DoxyCode}


the keys\+:


\begin{DoxyItemize}
\item {\ttfamily user/tests/storage/array/\#0}, and
\item {\ttfamily user/tests/storage/array/\#1}
\end{DoxyItemize}

represent array elements, while


\begin{DoxyItemize}
\item {\ttfamily user/tests/storage/map/\#0}, and
\item {\ttfamily user/tests/storage/map/\#1}
\end{DoxyItemize}

do not, since the key set also contains the key $\ast$$\ast${\ttfamily user/tests/storage/map/key}$\ast$$\ast$. The following example shows that the storage plugin \href{https://www.libelektra.org/plugins/yamlcpp}{\tt Y\+A\+ML C\+PP} handles this situation properly\+:


\begin{DoxyCode}
# Mount plugin
sudo kdb mount config.yaml user/tests/storage yamlcpp

# Create an array containing two elements
kdb set user/tests/storage/array/#0 one
kdb set user/tests/storage/array/#1 two

# The plugin creates an array parent key
# that stores the basename of the last element
kdb getmeta user/tests/storage/array array
#> #1

# Add an array that contains a single element
kdb set user/tests/storage/map/#0
kdb getmeta user/tests/storage/map array
#> #0

# After we add `user/tests/storage/map/key`,
# `user/tests/storage/map` is not an array any more.
kdb set user/tests/storage/map/key three
kdb getmeta user/tests/storage/map array
# RET: 1

# Adding a another key that uses array syntax below
# `user/tests/storage/map` does not change this.
kdb set user/tests/storage/map/#1 four
kdb getmeta user/tests/storage/map array
# RET: 1

# If we remove the key `user/tests/storage/map/key`, then
# `user/tests/storage/map` represents an array again.
kdb rm user/tests/storage/map/key
kdb ls user/tests/storage/map
#> user/tests/storage/map
#> user/tests/storage/map/#0
#> user/tests/storage/map/#1
kdb getmeta user/tests/storage/map array
#> #1

# Undo modifications to the key database
kdb rm -r user/tests/storage
sudo kdb umount user/tests/storage
\end{DoxyCode}
