Closed elado closed 7 years ago
Yay, I just wrote a demo, not simple.
import React from "react"
import { types, getSnapshot } from "mobx-state-tree"
import { observer } from "mobx-react"
import { inspect, render } from "mobx-state-tree-playground"
const Author = types.model('Author', {
id: types.identifier(),
name: types.string
})
const Category = types.model('Category', {
id: types.identifier(),
name: types.string
})
const Book = types.model('Book', {
id: types.identifier(),
title: types.string,
author: types.reference(Author),
categories: types.array(types.reference(Category))
})
const AppModel = types.model({
books: types.map(Book),
authors: types.map(Author),
categories: types.map(Category)
}, {
addAuthor(authorData) {
const author = Author.create(authorData)
this.authors.put(author)
},
addBook(bookData) {
const book = Book.create(bookData)
this.books.put(book)
},
addCategory(categoryData) {
const category = Category.create(categoryData)
this.categories.put(category)
}
})
const store = AppModel.create({books: {}, authors: {}, categories: {}})
inspect(store)
//////////////////////// Convert function
function convertStore(store, data) {
const AuthorData = types.model('Author', {
id: types.identifier(),
name: types.string
}, {
afterAttach() {
store.addAuthor(getSnapshot(this))
}
})
const CategoryData = types.model('Category', {
id: types.identifier(),
name: types.string
}, {
afterAttach() {
store.addCategory(getSnapshot(this))
}
})
const BookData = types.model('Book', {
id: types.identifier(),
title: types.string,
author: AuthorData,
categories: types.array(CategoryData)
}, {
afterAttach() {
const bookData = getSnapshot(this)
store.addBook(Object.assign({}, bookData, {
author: this.author.id,
categories: this.categories.map(c => c.id)
}))
}
})
const DataStore = types.model('DataStore', {
books: types.array(BookData)
})
DataStore.create({books: data})
}
//////////////////// Test
const data = [
{
id: 'b1', title: 'b1',
author: { id: 'a1', name: 'a1' },
categories: [ { id: 'c1', name: 'c1' }, { id: 'c2', name: 'c2' } ]
},
{
id: 'b2', title: 'b2',
author: { id: 'a2', name: 'a2' },
categories: [ { id: 'c1', name: 'c1' }, { id: 'c3', name: 'c3' } ]
}
]
convertStore(store, data)
See in Playground%0A%0Aconst%20Category%20%3D%20types.model('Category'%2C%20%7B%0A%20%20%20%20id%3A%20types.identifier()%2C%0A%20%20%20%20name%3A%20types.string%0A%7D)%0A%0Aconst%20Book%20%3D%20types.model('Book'%2C%20%7B%0A%20%20%20%20id%3A%20types.identifier()%2C%0A%20%20%20%20title%3A%20types.string%2C%0A%20%20%20%20author%3A%20types.reference(Author)%2C%0A%20%20%20%20categories%3A%20types.array(types.reference(Category))%0A%7D)%0A%0Aconst%20AppModel%20%3D%20types.model(%7B%0A%20%20%20%20books%3A%20types.map(Book)%2C%0A%20%20%20%20authors%3A%20types.map(Author)%2C%0A%20%20%20%20categories%3A%20types.map(Category)%0A%7D%2C%20%7B%0A%20%20%20%20addAuthor(authorData)%20%7B%0A%20%20%20%20%20%20%20%20const%20author%20%3D%20Author.create(authorData)%0A%20%20%20%20%20%20%20%20this.authors.put(author)%0A%20%20%20%20%7D%2C%0A%20%20%20%20addBook(bookData)%20%7B%0A%20%20%20%20%20%20%20%20const%20book%20%3D%20Book.create(bookData)%0A%20%20%20%20%20%20%20%20this.books.put(book)%0A%20%20%20%20%7D%2C%0A%20%20%20%20addCategory(categoryData)%20%7B%0A%20%20%20%20%20%20%20%20const%20category%20%3D%20Category.create(categoryData)%0A%20%20%20%20%20%20%20%20this.categories.put(category)%0A%20%20%20%20%7D%0A%7D)%0A%0Aconst%20store%20%3D%20AppModel.create(%7Bbooks%3A%20%7B%7D%2C%20authors%3A%20%7B%7D%2C%20categories%3A%20%7B%7D%7D)%0Ainspect(store)%0A%0A%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%20Convert%20function%0Afunction%20convertStore(store%2C%20data)%20%7B%0A%20%20%20%20const%20AuthorData%20%3D%20types.model('Author'%2C%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20types.identifier()%2C%0A%20%20%20%20%20%20%20%20name%3A%20types.string%0A%20%20%20%20%7D%2C%20%7B%0A%20%20%20%20%20%20%20%20afterAttach()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20store.addAuthor(getSnapshot(this))%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%0A%0A%20%20%20%20const%20CategoryData%20%3D%20types.model('Category'%2C%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20types.identifier()%2C%0A%20%20%20%20%20%20%20%20name%3A%20types.string%0A%20%20%20%20%7D%2C%20%7B%0A%20%20%20%20%20%20%20%20afterAttach()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20store.addCategory(getSnapshot(this))%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%0A%0A%20%20%20%20const%20BookData%20%3D%20types.model('Book'%2C%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20types.identifier()%2C%0A%20%20%20%20%20%20%20%20title%3A%20types.string%2C%0A%20%20%20%20%20%20%20%20author%3A%20AuthorData%2C%0A%20%20%20%20%20%20%20%20categories%3A%20types.array(CategoryData)%0A%20%20%20%20%7D%2C%20%7B%0A%20%20%20%20%20%20%20%20afterAttach()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20const%20bookData%20%3D%20getSnapshot(this)%0A%20%20%20%20%20%20%20%20%20%20%20%20store.addBook(Object.assign(%7B%7D%2C%20bookData%2C%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20author%3A%20this.author.id%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20categories%3A%20this.categories.map(c%20%3D%3E%20c.id)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D))%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%0A%0A%20%20%20%20const%20DataStore%20%3D%20types.model('DataStore'%2C%20%7B%0A%20%20%20%20%20%20%20%20books%3A%20types.array(BookData)%0A%20%20%20%20%7D)%0A%0A%20%20%20%20DataStore.create(%7Bbooks%3A%20data%7D)%0A%7D%0A%0A%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%20Test%0Aconst%20data%20%3D%20%5B%0A%20%20%7B%0A%20%20%20%20id%3A%20'b1'%2C%20title%3A%20'b1'%2C%0A%20%20%20%20author%3A%20%7B%20id%3A%20'a1'%2C%20name%3A%20'a1'%20%7D%2C%0A%20%20%20%20categories%3A%20%5B%20%7B%20id%3A%20'c1'%2C%20name%3A%20'c1'%20%7D%2C%20%7B%20id%3A%20'c2'%2C%20name%3A%20'c2'%20%7D%20%5D%0A%20%20%7D%2C%0A%20%20%7B%0A%20%20%20%20id%3A%20'b2'%2C%20title%3A%20'b2'%2C%0A%20%20%20%20author%3A%20%7B%20id%3A%20'a2'%2C%20name%3A%20'a2'%20%7D%2C%0A%20%20%20%20categories%3A%20%5B%20%7B%20id%3A%20'c1'%2C%20name%3A%20'c1'%20%7D%2C%20%7B%20id%3A%20'c3'%2C%20name%3A%20'c3'%20%7D%20%5D%0A%20%20%7D%0A%5D%0A%0AconvertStore(store%2C%20data)%0A)
There is no included solution yet, but for a low boilerplate solution you can check out normalizr and use it :)
addFetchedData(data){
const author = new schema.Entity('authors')
const category = new schema.Entity('categories')
const book = new schema.Entity('books', {
author,
categories: [category]
})
const {entities} = normalize(data, [book])
this.authors.merge(entities.authors)
this.categories.merge(entities.categories)
this.books.merge(entities.books)
}
Wow! Nearly perfect for me!
Thanks!
Thank you so much! normalizr
is indeed where I was aiming. Would be interesting to write a wrapper that translates MST models to normalizr, so all of that is seamless. I'll explore this direction.
Closing for now :)
I want to have a normalized db store, including relationships.
This is straightforward to build, but inserting the data may become complex.
If the server I'm talking to returns:
My
Book
model has aauthor: types.reference(Author)
andcategories: types.array(Category)
, just inserting aBook
into a collection doesn't insertauthor
andcategories
to the right places in the tree.Ideally I could throw entities in some structure at the store and it'll upsert them by type and ID, walk through the
reference
properties and do that recursively.Is there anything like that in MST, or anything planned?