Upsert Function Question

#1

I’m playing around with the Type System & the Upsert function. I’m using a Location Type for this example.

  1. I’m entering this command:
    Location.make({ id: ‘test_01’ }).upsert();

  2. If I execute the command again…

  3. Here’s the error that returns:
    {
    “id” : “8625.356580”,
    “codes” : [ “NonNullField” ],
    “key” : “c3.engine.database.DbException_validationErrors”,
    “template” : “{}”,
    “parameters” : [ “Write failed: Value is required for field mode in type Location” ]
    }

I know makes more sense to use merge instead of using upsert again as there’s no need to upsert the same Location again. I’d like to drill down on the why the error is occuring/why can’t I use upsert again.

I see in the documentation, that upsert “Creates an instance of a C3 type if it doesn’t exist or updates it if it does.” Shouldn’t the second command just “update” (quotes as there’s nothing new in the second command to update) the “test_01” instance?

Does it failed because that since I’ve already upserted a “test_01” and haven’t specified new data for fields? Would appreciate any help/input on this.

0 Likes

#2

Location.mode is a required field with the annotation @db(postDefault="'Points'"), which means that on object creation (at the database layer) if no value is provided for mode, use the default value "Points".

You can verify this by doing Location.fetch after the first upsert—your object’s mode field will have value "Points".

You said “there’s nothing new in the second command to update”, but that’s not actually true. update and upsert, when not provided with a srcObj argument, update all fields. Here’s the documentation for srcObj:

If specified, the initial state of obj before any updates. The actual update to the obj will be only the diff between the obj and srcObj. If not specified, the obj will completely replace the existing one.

When you call Location.upsert a second time for that same id, upsert says “take exactly what is provided here and persist it”. But this time, mode is undefined, and the object is not being newly created, so the postDefault annotation does not apply. This upsert is effectively attempting to remove the mode field value. That is why you are getting an error for a missing field.

2 Likes

#3

@matt thanks for the clarification, especially with the srcObj argument. With this in mind, receiving the error makes sense now.

0 Likes

#4

From “This upsert is effectively attempting to remove the mode field value. That is why you are getting an error for a missing field.” I deduce that updating the mode field from non-null to null is not a valid update. What is the “input obj” in the upsert documentation?
Similarly, documentation of merge confuses me around null: “Merging an obj instance by default only updates the non-null field values in the input obj. Non-null field values are ignored. Nullness of field values is honored at every level for fields that have an included type (e.g. non-entity type) as their value type.” Could you please give an example?
Thanks

0 Likes

#5

In this specific case, yes—if you check the documentation for the Location type, you will see that mode is a required field.

update and upsert are member functions, so the “input obj” is the object on which the function is called.

1 Like