From aa30bac2d6ba80e6d02906ed6f451451eb492bd6 Mon Sep 17 00:00:00 2001 From: Noah Gentile Date: Thu, 9 Jan 2025 15:12:11 -0800 Subject: [PATCH] fix: allow mutation selection without passing a patch builder --- src/data/transaction.ts | 27 +++++++++++++++++++++++++- test/client.test.ts | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/data/transaction.ts b/src/data/transaction.ts index 310a1e66..c8957d2e 100644 --- a/src/data/transaction.ts +++ b/src/data/transaction.ts @@ -7,6 +7,7 @@ import type { IdentifiedSanityDocumentStub, MultipleMutationResult, Mutation, + MutationSelection, PatchOperations, SanityDocument, SanityDocumentStub, @@ -213,6 +214,13 @@ export class Transaction extends BaseTransaction { * @param patchOps - Operations to perform, or a builder function */ patch(documentId: string, patchOps?: PatchBuilder | PatchOperations): this + /** + * Performs a patch on the given selection. Can either be a builder function or an object of patch operations. + * + * @param selection - An object with `query` and optional `params`, defining which document(s) to patch + * @param patchOps - Operations to perform, or a builder function + */ + patch(patch: MutationSelection, patchOps?: PatchBuilder | PatchOperations): this /** * Adds the given patch instance to the transaction. * The operation is added to the current transaction, ready to be commited by `commit()` @@ -220,9 +228,15 @@ export class Transaction extends BaseTransaction { * @param patch - Patch to execute */ patch(patch: Patch): this - patch(patchOrDocumentId: Patch | string, patchOps?: PatchBuilder | PatchOperations): this { + patch( + patchOrDocumentId: Patch | MutationSelection | string, + patchOps?: PatchBuilder | PatchOperations, + ): this { const isBuilder = typeof patchOps === 'function' const isPatch = typeof patchOrDocumentId !== 'string' && patchOrDocumentId instanceof Patch + const isMutationSelection = + typeof patchOrDocumentId === 'object' && + ('query' in patchOrDocumentId || 'id' in patchOrDocumentId) // transaction.patch(client.patch('documentId').inc({visits: 1})) if (isPatch) { @@ -239,6 +253,17 @@ export class Transaction extends BaseTransaction { return this._add({patch: patch.serialize()}) } + /** + * transaction.patch( + * {query: "*[_type == 'person' && points >= $threshold]", params: { threshold: 100 }}, + * {dec: { points: 100 }, inc: { bonuses: 1 }} + * ) + */ + if (isMutationSelection) { + const patch = new Patch(patchOrDocumentId, patchOps || {}, this.#client) + return this._add({patch: patch.serialize()}) + } + return this._add({patch: {id: patchOrDocumentId, ...patchOps}}) } } diff --git a/test/client.test.ts b/test/client.test.ts index eff78dcd..97c4f4fd 100644 --- a/test/client.test.ts +++ b/test/client.test.ts @@ -2379,6 +2379,48 @@ describe('client', async () => { ]) }) + test('patch can use a mutation selector', () => { + const transaction = getClient() + .transaction() + .patch( + { + query: '*[_id in $ids]', + params: {ids: ['abc123', 'foo.456']}, + }, + {inc: {count: 1}}, + ) + + expect(transaction.serialize()).toEqual([ + { + patch: { + query: '*[_id in $ids]', + params: {ids: ['abc123', 'foo.456']}, + inc: {count: 1}, + }, + }, + ]) + + const transactionWithCallback = getClient() + .transaction() + .patch( + { + query: '*[_id in $ids]', + params: {ids: ['abc123', 'foo.456']}, + }, + (p) => p.inc({count: 1}), + ) + + expect(transactionWithCallback.serialize()).toEqual([ + { + patch: { + query: '*[_id in $ids]', + params: {ids: ['abc123', 'foo.456']}, + inc: {count: 1}, + }, + }, + ]) + }) + test.skipIf(isEdge)('executes transaction when commit() is called', async () => { const mutations = [{create: {_type: 'foo', bar: true}}, {delete: {id: 'barfoo'}}] nock(projectHost())