Security News
NVD Backlog Tops 20,000 CVEs Awaiting Analysis as NIST Prepares System Updates
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
@sanity/mutate
Advanced tools
Experimental toolkit for working with Sanity mutations in JavaScript & TypeScript
[!WARNING] Disclaimer: This is work in progress, use at own risk!
Experimental toolkit for working with Sanity mutations in JavaScript & TypeScript
_key
's to objects in arrays, so you don't have to.import {
at,
create,
createIfNotExists,
patch,
SanityEncoder,
set,
setIfMissing,
} from '@sanity/mutate'
const mutations = [
create({_type: 'dog', name: 'Fido'}),
createIfNotExists({_id: 'document-1', _type: 'someType'}),
createIfNotExists({_id: 'other-document', _type: 'author'}),
patch('other-document', [
at('published', set(true)),
at('address', setIfMissing({_type: 'address'})),
at('address.city', set('Oslo')),
]),
]
// get a projectId and dataset at sanity.io
const projectId = '<projectId>'
const dataset = '<dataset>'
// Submit mutations to the Sanity API
fetch(`https://${projectId}.api.sanity.io/v2023-08-01/data/mutate/${dataset}`, {
method: 'POST',
mode: 'cors',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(SanityEncoder.encode(mutations)),
})
.then(response => response.json())
.then(result => console.log(result))
create(document: SanityDocument)
: Create a new documentcreateIfNotExists(document: SanityDocument)
: Create a new document if it does not existcreateOrReplace(document: SanityDocument)
: Create a new document or replace an existing onedelete(documentId: SanityDocument)
: Delete a document (aliases: del
, destroy
)patch(documentId: string, patches: Patch | Patch[], options?: {ifRevision?: string})
: Patch a document. Can
optionally provide a revisionId
for optimistic locking. If
the current document revision doesn't match the given revision the patch mutation will fail when applied.A patch is a combination of a node path and an operation. The node path is a simplified JSONMatch path or an array of path segments that points to a specific node in the document. The operation is one of the operations described below.
at(path: Path | string, operation: Operation)
: Create a patch from a path and an operationat('foo.bar', set('baz'))
// equivalent to the above
at(['foo', 'bar'], set('baz'))
at(['array[0]'], insert('baz'))
// Set a value deep into an array of objects addressed by `_key`
at(['people', {_key: 'xyz'}, 'name'], set('Bjørge'))
// equivalent to the above, using a serialized path:
at('people[_key=="xyz"].name', set('Bjørge'))
set(value: any)
: Set the value of the node to the given value
setIfMissing(value: any)
: Set the value of the node to the given value
if the node has no valueunset()
: Remove the node from the documentassign(value: object)
: Do a shallow merge of the node with the given value. If the node is an object, the value will
be merged into the object similar to Object.assign(<currentValue>, value)
.unassign(attributes: string[])
: Remove the given attributes from the existing value.prepend(items: any[])
: Prepend the given items to the beginning of the arrayappend(items: any[])
: Append the given items to the end of the arrayinsert(items: any | any[], position: "before" | "after", referenceItem: number | {_key: string})
: Insert the given
items before or after the given before
or after
item. If before
or after
is not provided, the items will be
inserted at the beginning or end of the array.truncate(startIndex: number, endIndex?: number)
: Remove items from the array starting at startIndex
and ending
at endIndex
. If endIndex
is not provided, all items after startIndex
will be removed.replace(items: any | any[], referenceItem: number | {_key: string})
: Replaces the referenceItem
(addressed by
index or _key) with the given item
or items
. If items
is an array, referenceItem
will be replaced by the
items and any existing elements that comes after referenceItem
will be shifted to the right.upsert(items: any | any[], position: "before" | "after", referenceItem: number | {_key: string})
: Upsert one or more items
into the array. If the items match existing items in the array, the existing items will be replaced with the given
items. If the items do not match any existing items, it will be inserted into the array. ThereferenceItem
specifies a reference item to place missing items relative to. If. If not provided, any missing items will be inserted at
the beginning or end of the array, depending on position
. The position
option can be used to specify where to insert the item if it does not
match any existing items. If not provided, the item will be inserted at the end of the array.inc(value: number)
: Increment the number by the given valuedec(value: number)
: Decrement the number by the given valuediffMatchPatch(patch: string)
: Apply an incremental text patch to the current string. Read more
about diffMatchPatch.Define a set of operations and turn it into a patch mutation that can be applied on a set of documents
const patches = [
at('metadata', setIfMissing({})), // make sure metadata object exists
at('metadata.published', set(true)),
at('metadata.publishedAt', set(new Date().toISOString())),
]
const mutations = ['document-1', 'document-2', 'document-3'].map(id =>
patch(id, patches),
)
// commit mutations to datastore
commitMutations(mutations)
Mutations can be applied to an in-memory collection of documents
import {applyInCollection} from '@sanity/mutate/_unstable_apply'
import {createIfNotExists, del} from '@sanity/mutate'
const initial = [{_id: 'deleteme', _type: 'foo'}]
const updated = applyInCollection(initial, [
createIfNotExists({_id: 'mydocument', _type: 'foo'}),
createIfNotExists({_id: 'anotherDocument', _type: 'foo'}),
del('deleteme'),
])
console.log(updated)
/*=>
[
{ _id: 'mydocument', _type: 'foo' },
{ _id: 'anotherDocument', _type: 'foo' }
]
*/
Note: when applying mutations on a collection, referential integrity is preserved. This means that if a mutation is effectively a noop (e.g. nothing actually changed), the same object reference will be returned.
import {applyInCollection} from '@sanity/mutate/_unstable_apply'
import {at, createIfNotExists, patch, set} from '@sanity/mutate'
const initial = [
{
_id: 'someDoc',
_type: 'foo',
value: 'ok',
nested: {value: 'something'},
otherNested: {message: 'something else'},
},
]
const updated = applyInCollection(initial, [
createIfNotExists({_id: 'someDoc', _type: 'foo'}),
patch('someDoc', [at('value', set('ok'))]),
patch('someDoc', [at('nested.value', set('something'))]),
])
// the mutation didn't cause anything to change
console.log(initial === updated)
//=> true
This is also the case for nodes unaffected by the mutations:
import {applyInCollection} from '@sanity/mutate/_unstable_apply'
import {at, createIfNotExists, patch, set} from '@sanity/mutate'
const initial = [
{
_id: 'someDoc',
_type: 'foo',
value: 'ok',
nested: {value: 'something'},
otherNested: {message: 'something else'},
},
]
const updated = applyInCollection(initial, [
createIfNotExists({_id: 'someDoc', _type: 'foo'}),
patch('someDoc', [at('value', set('ok'))]),
patch('someDoc', [at('nested.value', set('something'))]),
patch('someDoc', [at('otherNested.message', set('hello'))]),
])
// the `nested` object unaffected by the mutation
console.log(initial[0].nested === updated[0].nested)
//=> true
Alternatively, a patch mutation can be applied to a single document as long as its id matches the document id of the mutation:
import {applyPatchMutation} from '@sanity/mutate/_unstable_apply'
import {at, insert, patch, setIfMissing} from '@sanity/mutate'
const document = {_id: 'test', _type: 'foo'}
const updated = applyPatchMutation(
document,
patch('test', [
at('title', setIfMissing('Foo')),
at('cities', setIfMissing([])),
at('cities', insert(['Oslo', 'San Francisco'], 'after', 0)),
]),
)
console.log(updated)
/*=>
{
_id: 'test',
_type: 'foo',
title: 'Foo',
cities: [ 'Oslo', 'San Francisco' ]
}
*/
To better align with a strict type system, @sanity/mutate
differs slightly from the Sanity API when applying patches. Although all the mutation types you can express with @sanity/mutate
can also be expressed as Sanity API mutations, the inverse is not necessarily true; The Sanity API (e.g. a listener) may produce patches that can't be represented in @sanity/mutate
without an extra conversion step that takes the current document into account. In addition, applying a patch in @sanity/mutate
behaves differently from applying the same patch using the Sanity API on a few accounts:
set
andsetIfMissing
does not create intermediate empty objects - Using the Sanity API, set
and setIfMissing
will create intermediate empty objects if any object along the given path doesn't already exist. In @sanity/mutate
, these patches will only apply to already existing objects.@sanity/mutate
patch can only target a single document node.0.8.0 (2024-08-07)
FAQs
Experimental toolkit for working with Sanity mutations in JavaScript & TypeScript
The npm package @sanity/mutate receives a total of 89,418 weekly downloads. As such, @sanity/mutate popularity was classified as popular.
We found that @sanity/mutate demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 63 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.