Format¶
Encoding¶
The encoding can be set when creating the isotope, e.g.:
const isotope = new Isotope<T>({
format: { encoding: "text" },
domain: "<domain>",
key: "<keyof T>"
})
options.format.encoding: "json"
-
All values are JSON-encoded, which means that strings are double-quoted, whereas numbers and booleans are written literally:
{ "Name": "example", "Attributes": [ { "Name": "active", "Value": "true" }, { "Name": "props.image", "Value": "\"busybox\"" }, { "Name": "props.cpus", "Value": "2" }, { "Name": "props.memory", "Value": "2048" }, { "Name": "tags[]", "Value": "\"TAG_1\"" }, { "Name": "tags[]", "Value": "\"TAG_2\"" } ] }
If you don't plan to use the SimpleDB domain from a non-Isotope client, you should always stick with JSON-encoding because it is more safe than text encoding and comes with no limitations.
options.format.encoding: "text"
-
Isotopes provides the ability to use an alternate encoding and store strings as literals so they are written without quotes:
{ "Name": "example", "Attributes": [ { "Name": "active", "Value": "true" }, { "Name": "props.image", "Value": "busybox" }, { "Name": "props.cpus", "Value": "2" }, { "Name": "props.memory", "Value": "2048" }, { "Name": "tags[]", "Value": "TAG_1" }, { "Name": "tags[]", "Value": "TAG_2" } ] }
When decoding the data, we intercept
JSON.parse
assuming that we encountered a literal string if it fails to decode. It's a hack and yes, imposes some limitations:-
Numbers that are encoded as strings (e.g. house numbers, because they can exhibit values as
2A
etc.) are interpreted as numbers when decoded withJSON.parse
. Countermeasure: ensure that numbers are typed as numbers, or string fields contain at least one non-number character. -
If strings accidentally contain valid JSON, e.g.
{}
, the value is parsed as JSON and the field gets assigned that precise value. This also breaks type safety. Countermeasure: ensure that your strings are never valid JSON by prepending some character that makesJSON.parse
fail.
As enforcing as those restrictions may seem to be, it is often true that the properties and characteristics of the data are known a-priori and those special cases can be ruled out with great certainty. This also means that querying the data from other parts of your system gets easier as string values don't need to be enclosed into quotes (and don't start thinking about
LIKE
queries) which is far more user-friendly. -
Flattening¶
Isotopes enables the storage of nested JSON objects within SimpleDB which itself is a key-value store with the ability to query using SQL expressions. In order to be compatible with SimpleDB, objects need to be flattened to match the key-value nature of SimpleDB.
Objects¶
Nested objects are flattened by concatenating the keys with .
and associating
the value of the nested object's key with the concatenated path, e.g.:
{ "foo": { "bar": "baz" } }
becomes:
{ "Name": "foo.bar", "Value": "baz" }
Arrays¶
There are two flavors for nested arrays, both with different use cases. Which
flavor is used is actually controlled using the options.format.multiple
option when creating the isotope:
options.format.multiple = true
(default)-
Array values are written as separate attributes. This is especially useful for arrays with primitive values (
string
,number
andboolean
) to enable indexing and queryability. Field names are suffixed with[]
to indicate an array of values. However, note that SimpleDB doesn't guarantee order of attributes, so only use this if the order of the entries inside the array doesn't matter, e.g. for tagging:{ "tags": ["TAG_1", "TAG_2"] }
becomes:
{ "Name": "tags[]", "Value": "TAG_1" }, { "Name": "tags[]", "Value": "TAG_2" }
options.format.multiple = false
-
Arrays are written as a single attribute using
"json"
encoding. While this guarantees the order of array values, it is certainly not possible to query for separate values using SQL expressions as they are encoded in JSON syntax, e.g.:{ "tags": ["TAG_1", "TAG_2"] }
becomes:
{ "Name": "tags", "Value": "[\"TAG_1\", \"TAG_2\"]" }
Example¶
Assume we want to persist the type specified in the getting started guide.
When persisting an object of this type with multiple = true
and "text"
encoding, the flattened data that is persisted in SimpleDB will look like this:
{
"Name": "example",
"Attributes": [
{ "Name": "active", "Value": "true" },
{ "Name": "props.image", "Value": "busybox" },
{ "Name": "props.cpus", "Value": "2" },
{ "Name": "props.memory", "Value": "2048" },
{ "Name": "tags[]", "Value": "TAG_1" },
{ "Name": "tags[]", "Value": "TAG_2" }
]
}