I’m unable to get this “Upsert” recipe to work. I keep getting an “instance already exists” error with the following implementation:
import { query as q } from 'faunadb'
import faunadbClient from '/components/api/faunadb/client'
export default async(req, res) => {
try {
await faunadbClient.query(
q.CreateFunction({
name: 'upsert',
body: q.Query(
q.Lambda(
['ref', 'data'],
q.If(
q.Exists(q.Var('ref')),
q.Update(q.Var('ref'), q.Var('data')),
q.Create(q.Var('ref'), q.Var('data'))
)
)
)
})
)
await faunadbClient.query(
q.Call(
q.Function('upsert'),
q.Ref(q.Collection(req.query.collection), req.query.id),
{
data: req.body
}
)
)
res.status(200).end()
} catch (e) {
res.status(500).json({ error: e.message })
}
}
However, if I run the same query on a Update
specific endpoint, the document values are updated fine without error, like so:
import { query as q } from 'faunadb'
import faunadbClient from '/components/api/faunadb/client'
export default async(req, res) => {
try {
await faunadbClient.query(
q.Update(
q.Ref(q.Collection(req.query.collection), req.query.id),
{
data: req.body,
}
)
)
res.status(200).end()
} catch (e) {
res.status(500).json({ error: e.message })
}
}
Any ideas on what is going wrong here?
Sorry, I just realised the problem. I’m trying to create the ‘upsert’ function when it already exists. This can be ignored/closed/deleted. Sorry for the unnecessary noise!
If anyone is interested or can recommend a better approach, this is how I’m creating functions only if they don’t already exist:
import { query as q } from 'faunadb'
import faunaDBClient from '/components/api/faunadb/client'
export default async(name, body) => {
try {
let customFunctions = []
let exists = false
await faunaDBClient.query(
q.Paginate(q.Functions())
).then((ret) => {
customFunctions = ret.data
})
customFunctions.forEach(customFunction => {
exists = customFunction['@ref'].id === name ? true : exists
})
if (!exists) {
await faunaDBClient.query(
q.CreateFunction({ name, body })
)
}
return true
} catch (e) {
return e
}
}
Which can be used to create the ‘upsert’ function like so:
await FaunaDBCreateFunction('upsert', q.Query(
q.Lambda(
['ref', 'data'],
q.If(
q.Exists(q.Var('ref')),
q.Update(q.Var('ref'), q.Var('data')),
q.Create(q.Var('ref'), q.Var('data'))
)
)
))
Functions are Documents, too! So similar to how you can “upsert” a Document, you can upsert a Function.
If you’re using JS, you can create a CreateOrUpdateFunction
helper
const CreateOrUpdateFunction = (params) => q.Let(
{
name: Select("name", params),
params
},
q.If(
q.Exists(q.Function(q.Var("name"))),
q.Update(q.Function(q.Var("name")), q.Var("params")),
q.CreateFunction(q.Var("params"))
),
)
The Let
here helps to reduce how big the final query is. Otherwise, we would duplicate the entire set of params for both the create case as well as the update case.
Use it as a replacement for CreateFunction
await faunadbClient.query(
CreateOrUpdateFunction({
name: 'upsert',
body: q.Query(
q.Lambda(
['ref', 'data'],
q.If(
q.Exists(q.Var('ref')),
q.Update(q.Var('ref'), q.Var('data')),
q.Create(q.Var('ref'), q.Var('data'))
)
)
)
})
)
You can create similar helpers for CreateOrUpdateDatabase
, CreateOrUpdateCollection
and CreateOrUpdateRoles
. You can do so with Indexes as well, but it would have to have extra validation, since you cannot edit terms or values once an Index is created.
2 Likes
system
closed
March 20, 2022, 7:04am
#6
This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.