3 ms·
Absolutely. Instant has similar design goals to Rails and ActiveRecord Here are some parallels your example: A. ActiveRecord: ``` post = Post.find_by(author
by stopachka 2y ago
Absolutely. Instant has similar design goals to Rails and ActiveRecord
Here are some parallels your example:
A. ActiveRecord:
```
post = Post.find_by(author: "John Smith") post.author.email = "john@example.com" post.save
```
B. Instant:
```
db.transact(
tx.users[lookup('author', 'John Smith')].update({ email: 'john@example.com' }),
);
```
> In React/Vue/Solid, I want to say express things like this:
Here's what the React/Vue code would look like:
```
function BlogPostDetailComponent(props) {
// `useQuery` is equivelant to the `subscribe` that you mentioned:
const { isLoading, data, error } = db.useQuery({posts: {author: {}, $: {where: { id: props.id }, } })
if (isLoading) return ...
if (error) return ..
function updateAuthorName(newName) {
// `db.transact` does what you mentioned:
// it attempts to persist any pending changes to browser storage, then
// sync to remote db, rolling back changes if there's a failure, and
// gives an easy way to show an error toast if the update failed. (it's awaitable)
db.transact(
tx.authors[author.id].update({name: newName})
)
}
return (
<>
...
</>
)
}
```
- remolacha 2y agoMaybe a dumb question, but why do I have to wrap in `db.transact` and `tx.*`? Why can't I just have a proxy object that handles that stuff under the hood? Naively, it seems more verbose than necessary. Also, I like that in Rails, there are ways to mutate just in memory, and then ways to push the change to DB. I can just assign, and then changes are only pushed when I call `save()`. Or if I want to do it all-in-one, I can use something like `.update(..)`. In the browser context, having this separation feels most useful for input elements. For example, I might have a page where the user can update their username. I want to simply pass in a value for the input element (controlled input) ex. ```jsx <input value={user.name} ... /> ``` But I only want to push the changes to the db (save) when the user clicks the save button at the bottom of the page. If any changes go straight to the db, then I have two choices: 1. Use an uncontrolled input element. This is inconvenient if I want to use something like Zod for form validation 2. Create a temporary state for the WIP changes, because in this case I don't want partial, unvalidated/unconfirmed changes written to either my local or remote db.
- stopachka 2y agoThis is a great question. We are working on a more concise transaction API, and are still in the design phase. Writing a `user.save()` could be a good idea, but it opens up a question about how to do transactions. For example, saving _both_ user and post together). I could see a variant where we return proxied objects from `useQuery`. What would your ideal API look like?
- Aeolun 2y ago> What would your ideal API look like? He gave an example in the first post in this chain xD
- aidos 2y agoWe have an internal lib for data management that’s philosophically similar to linear too. I opted for having required transactions for developer safety. Imagine that you support the model discussed above where it’s possible to update the local store optimistically without syncing back to the db. Now you’re one missing .save() away from having everything look like it’s working in the frontend when really nothing is persisting. It’s the sort of foot gun that you might regret supporting. Our model is slightly different in that we require the .save() on objects to create the mutation for the sync. The primary reason is that we’re syncing back to real tables in Postgres and require referential integrity etc to be maintained. tx((db) => { const author = new Author(db) author.save() article.name = “New name” article.author = author article.save() } Mutating an object outside of a transaction is a hard error. Doing the mutation in a transaction but failing to call save within the same transaction is a hard error too.
- sabbaticaldev 2y agoA thenable API from save() could remove the need of a explicit tx management which is a worse devEx
- aidos 2y agoI’m not quite seeing what you mean. What you mind redoing the example above for my benefit? We have controllers that all the users actions are funnelled through. The top level functions in there are wrapped in transactions so in practice it’s not something you manually wrangle.