Is there a generated "upsert" mutation?

If not, is it possible to define a custom resolver with the SQL needed to perform this operation?

Hi @zach-is-my-name,

We don’t have such functionality now.

Thanks,
Ilya

Hey @zach-is-my-name!

Yeah we currently don’t have a native API operation for merge/upsert. You’d have to tackle it with a custom resolver, which is 100% possible.

npm install -g 8base-cli

8base login

8base init myProject

=> [Select your workspace]

8base g resolver updateOrCreate -s=js

Will give you a template for the resolver.

One strategy might be to accept the table name as the first arg and then the data as the second. This way you could potentially use one resolver for upserting against all your tables.

updateOrCreate('tableName', { title: "Some Title" })

If the fields that you are trying to match don’t have a unique or mandatory constraint, you’ll need to use updateByFilter to search for records to update. For example…

mutation {
  userUpdateByFilter(filter: {
    email: {
      equals: "some@email.com"
    }
  }, data: {
    email: {
      set: "somenew@email.com"
    },
    firstName: {
      set: "Steve"
    },
    lastName: {
      set: "Jones"
    }
  }) {
    count
  }
}

In this case, if the count returned 0 you’d then want to make a create request using the same data.

Hope this helps and feel free to ask more questions.

Sebastian

2 Likes

I’d love to be able to do upsert within relations as I’m sometime not 100% sure a child already exists or not. Is there any way to bring a custom resolver within the create/update/connect/reconnect/disconnect interface @sebastian.scholl?

Hey @gahabeen! If you write a before trigger on update operation on a table, it will always run before a record in that table is updated - whether or not it’s being called directly or through a relationship.

That said, if you set a before trigger on update on the parent table, you’ll be able to check the payload for an update happening on the related record… For example:

// function code

if (event.data.childRelationship.update) {
  const { childRecord } = await ctx.api.gqlRequest(FIND_RECORD_QUERY, {
    uniqueIdentifier: event.data.childRelationship.update.uniqueIdentifier;
  });

  if (!childRecord) {
    event.data.childRelationship['create'] = event.data.childRelationship.update;
    delete event.data.childRelationship.update;
  }
}

// maybe... more code

return {
  data: event.data
}

Given that something like this would happen before the update, you’d be able to change the relational data passed to the update operation before it gets executed.

Let me know if this makes sense or helps you get on the right track.

2 Likes

Thanks, I definitely need to use more of the trigger’s power!
I really like your idea :slight_smile:

1 Like

Hi @sebastian.scholl, are the trigger payloads still structured like your example above? I’m doing some testing and that’s not what I’m seeing, but it’s entirely possible I’ve got the wrong end of the stick.

For context, I’m only interested in learning about when table relationships are created/updated.

Here is what I’m seeing when I connect a record in one table with a record in another table:

  • Before{record}Update: data does contain data for ALL connected records. But because originalObject does not, I don’t know where the connection was made (i.e. it’s impossible to run a diff on these objects).
  • After{record}Update: data does not contain data for connected records, but originalObject does. This is the opposite of before, but again does not allow me to run a diff and see what changed.
  • Before{connectedRecord}Update: trigger not invoked at all.
  • After{connectedRecord}Update: trigger not invoked at all.

Neither of these events contain a event.data.childRelationship.update property like you mention above though, which makes me wonder if things have changed or if I’m doing something wrong. And triggers on the parent/connected table don’t seem to be invoked at all — again, which seems to be at odds with your post.

Given the above (and I guess this is the more important point), there doesn’t seem to be a way to trigger custom code to run when one record is connected to another. That’s because the before/after triggers fire without telling you what actually happened (and without giving you a way to work it out for yourself). Unless, I’m mistaken! :grimacing: :see_no_evil:

Sorry for the long-winded post, but I’d love to hear your thoughts. Thank you.

Hey Bri -

Yeah your break down is correct. To detect relationship changes you’ll need to use a before trigger and run a Query to get the relationship info. For example;

export default (event, ctx) => {
  const NewChildID = event.data.childRelationship.connect.id

  const { parent: { child } } = await ctx.api.gqlRequest(`
    query($id: ID) { 
      parent(id: $id) {
        child { id }
      }     
    }`,
    { id: event.data.id }
  )

  /*} At this point you have both id's of the connected records, old and new */

}

Hope this helps

Created a feature request for this, would appricate any comments to get it boosted.

2 Likes