How to update a struct that is saved in cayley using Schema lib?

schema

#1

I am trying to update a clinic using schema lib. I loaded the clinic using LoadTo but not sure what should I do now. The idea is to read a json file with the fields of the clinic I want to update. Here is a code sample that reproduces the situation (go run main.go): https://github.com/oren/cayley-docs/blob/611683dba544227420243432406b9172f777e312/how-to-guides/05-update-clinic/main.go#L138-L145

Currently I inserts but it creates another clinic. Is there a way to upsert or do I need to delete it first? If so, how do I delete it?

var clinic Clinic
checkErr(schema.LoadTo(nil, h, &clinic, id))
fmt.Println("clinic loaded", clinic)

clinic.Address1 = "Seasame st" // TODO: read this from the json file

id, err := insert(h, clinic)
checkErr(err)

Thanks!


#2

Currently the problem is that your Clinic object has no ID field defined, thus it will always execute insert.

Still, if you make add an ID field you will see two Address quads after an update.

There are two possible solutions:

  1. Create a transaction, “Save” the object using delete writer into transaction, and then save it again using normal writer. This will mark all old quads for removal in tx, but will preserve quads that are not changed (because them are added again in the same tx).
  2. Write an update manually: delete address quad and add a new address in the same tx.

#3

As soon as I add the ID to the clinic struct the manual update worked! I also added a transaction. Can you review my code and tell me if it looks good?

var clinic Clinic
t := cayley.NewTransaction()
checkErr(schema.LoadTo(nil, h, &clinic, id))
clinic.Address1 = "Seasame st"    // TODO: read this from the json file
clinic.OfficeTel = "999 999 9999" // TODO: read this from the json file
id, err := insert(h, clinic)
checkErr(err)
err = h.ApplyTransaction(t)
checkErr(err)

What are the pros and cons of the first approach you mentioned? Can you provide a snippet of code so I’ll understand what it looks like?

Thanks!


#4

Currently you don’t use transaction at all - you can verify it by removing all the code associated with t.

Second, it seems like you will have two address quads after an update (if it was set before an update) - you can check it by iterating over all quads from this id: qs.QuadIterator(quad.Subject, id).

The snippet for full delete and full insert will look like this:

tx := cayley.NewTransaction()
// mark old clinic quads for deletion
dw := graph.NewTxWriter(tx, graph.Delete)
_ = schema.WriteAsQuads(dw, oldClinic)
// mark new quads for insertion
iw := graph.NewTxWriter(tx, graph.Add)
_ = schema.WriteAsQuads(iw, newClinic)
// tx now contains only changed quads
_ = h.ApplyTransaction(tx)

and the second approach is to change only fields you need:

tx := cayley.NewTransaction()
tx.RemoveQuad(quad.Make(id, quad.IRI("address"), oldClinic.Address1, nil))
tx.AddQuad(quad.Make(id, quad.IRI("address"), newClinic.Address1, nil))
_ = h.ApplyTransaction(tx)

#5

Thanks you! I’ll give it a try this weekend.