Homebase React 0.5.0 | JSON Derived Relationships

Chris Smothers
Co-founder and CTO
· 6 minutes

Homebase React v0.5.0 simplifies relationships by automatically normalizing nested JSON transactions.

Now you can write

1transact([
2  { todo: { name: 'T1', project: { name: 'P1' } }
3])

Which is equivalent to

1transact([
2  { project: { id: -1, name: 'P1' }, 
3  { todo: { name: 'T1', project: -1} }
4])

In addition to simplifying the API for transactions we’ve also simplified schema maintenance.

Homebase React requires a schema on read to support relationships. Basically, instead of joining data at query time like in SQL, you specify how attributes are related up front so queries can be simpler.

With nested JSON transaction we can detect relationships at transaction time. This allows us to prompt you to add the correct schema if it’s missing. So even if you’re new to normalized data we’ll guide you to some reasonable defaults.

1const config = {}
2
3<HomebaseProvider config={config} />
4
5transact([{ item: { child: { name: 'A' }}}])
6// Throws =>
7`
8Error: The 'item.child' attribute should be a ref type of one.
9
10Add this to your config:  schema: { item: { child: { type: 'ref', cardinality: 'one' }}}
11`

And of course you can easily traverse your graph with entity.get

1const [t1] = useEntity({ todo: { name: 'T1' } })
2t1.get('project', 'name') // => 'P1'

Arrays

In addition to nested JSON objects we’ve added support for one level of nested arrays. It’s not full JSON support, no arrays of arrays [[1]], but it’s pretty close.

1transact([{ 
2  project: { 
3    name: 'P1', 
4    numbers: [1, 2, 3],
5    todos: [
6      { todo: { name: 'T1' } },
7      { todo: { name: 'T2' } }
8    ]
9  } 
10}])

To access array elements we’ve added several helpful features to the get API.

Get array index

1const [p1] = useEntity({ project: { name: 'P1' } })
2p1.get('numbers', 0, 'value') // => 1
3p1.get('todos', 0, 'ref', 'name') // => 'T1'

Implicit map over attribute

Omitting an index on an array type will automatically cause the next attributes to be mapped over all items in the array.

1const [p1] = useEntity({ project: { name: 'P1' } })
2p1.get('numbers', 'value') // => [1, 2, 3]
3p1.get('todos', 'ref', 'name') // => ['T1', 'T2']

Array attributes

You probably noticed the the attributes 'value' and 'ref'. These are special attributes on arrays. If an array element is a value like a string or a number you can access it with the value attribute. If an array element is a reference to a related entity then you can get that entity with the ref attribute.

Array order

Arrays also have a special 'order' attribute that contains a number representing the sort order of an array element. You can update this attribute to reorder an array.

1const [p1] = useEntity({ project: { name: 'P1' } })
2p1.get('numbers', 'value') // => [1, 2, 3]
3p1.get('numbers', 0, 'order') // => 1
4p1.get('numbers', 1, 'order') // => 2
5transact({ 'homebase.array': {
6  id: p1.get('numbers', 2, 'id'),
7  order: 1.5
8}})
9p1.get('numbers', 'value') // => [1, 3, 2]