@sanity/migrate
Version:
Tooling for running data migrations on Sanity.io projects
168 lines (140 loc) • 5.48 kB
text/typescript
import {describe, expect, test} from 'vitest'
import {toArray} from '../../../it-utils/index.js'
import {batchMutations} from '../batchMutations.js'
function byteLength(obj: unknown) {
return JSON.stringify(obj).length
}
describe('mutation payload batching', () => {
test('when everything fits into a single mutation request', async () => {
const first = {createIfNotExists: {_id: 'foo', _type: 'something', bar: 'baz'}}
const second = {patch: {id: 'foo', set: {bar: 'baz'}}}
const gen = async function* () {
yield first
yield second
}
const firstSize = JSON.stringify(first).length
const secondSize = JSON.stringify(second).length
const it = batchMutations(gen(), firstSize + secondSize)
expect(await it.next()).toEqual({done: false, value: {mutations: [first, second]}})
expect(await it.next()).toEqual({done: true, value: undefined})
})
test('when max batch is not big enough to fit all values', async () => {
const first = {createIfNotExists: {_id: 'foo', _type: 'something', bar: 'baz'}}
const second = {patch: {id: 'foo', set: {bar: 'baz'}}}
const gen = async function* () {
yield first
yield second
}
const firstSize = JSON.stringify(first).length
const it = batchMutations(gen(), firstSize)
expect(await it.next()).toEqual({done: false, value: {mutations: [first]}})
expect(await it.next()).toEqual({done: false, value: {mutations: [second]}})
expect(await it.next()).toEqual({done: true, value: undefined})
})
test('when each mutation is bigger than max batch size', async () => {
const first = {createIfNotExists: {_id: 'foo', _type: 'something', bar: 'baz'}}
const second = {patch: {id: 'foo', set: {bar: 'baz'}}}
const gen = async function* () {
yield first
yield second
}
const it = batchMutations(gen(), 1)
expect(await it.next()).toEqual({done: false, value: {mutations: [first]}})
expect(await it.next()).toEqual({done: false, value: {mutations: [second]}})
expect(await it.next()).toEqual({done: true, value: undefined})
})
test('when some mutations can be chunked, others not', async () => {
const first = {createIfNotExists: {_id: 'foo', _type: 'something', bar: 'baz'}}
const second = {patch: {id: 'foo', set: {bar: 'baz'}}}
// Note: this is an array of mutations and should not be split up as it may be intentional to keep it in a transaction
// todo: is it ok to include other mutations in the same batch as a transaction?
const third = [
{
createOrReplace: {
_id: 'foo',
_type: 'something',
bar: 'baz',
baz: 'qux',
},
},
{patch: {id: 'foo', set: {bar: 'baz'}}},
]
const gen = async function* () {
yield first
yield second
yield third
}
const it = batchMutations(gen(), byteLength(first) + byteLength(second))
expect(await it.next()).toEqual({done: false, value: {mutations: [first, second]}})
expect(await it.next()).toEqual({done: false, value: {mutations: third}})
})
})
//todo: verify if this is the default behavior we want
test('transactions are always in the same batch, but might include other mutations if they fit', async () => {
const first = {createIfNotExists: {_id: 'foo', _type: 'something', bar: 'baz'}}
const second = {patch: {id: 'foo', set: {bar: 'baz'}}}
// Note: this is an array of mutations and should not be split up as it may be intentional to keep it in a transaction
const transaction = {
mutations: [
{
createOrReplace: {
_id: 'foo',
_type: 'something',
bar: 'baz',
baz: 'qux',
},
},
{patch: {id: 'foo', set: {bar: 'baz'}}},
],
}
const fourth = {patch: {id: 'another', set: {this: 'that'}}}
const gen = async function* () {
yield first
yield second
yield transaction
yield fourth
}
const it = batchMutations(
gen(),
[first, second, transaction, fourth].reduce((l, m) => l + byteLength(m), 0),
)
expect(await toArray(it)).toEqual([
{mutations: [first, second]},
transaction,
{mutations: [fourth]},
])
expect(await it.next()).toEqual({done: true, value: undefined})
})
test('transactions are always batched as-is if preserveTransactions: true', async () => {
const first = {createIfNotExists: {_id: 'foo', _type: 'something', bar: 'baz'}}
const second = {patch: {id: 'foo', set: {bar: 'baz'}}}
// Note: this is an array of mutations and should not be split up as it may be intentional to keep it in a transaction
const transaction = {
mutations: [
{
createOrReplace: {
_id: 'foo',
_type: 'something',
bar: 'baz',
baz: 'qux',
},
},
{patch: {id: 'foo', set: {bar: 'baz'}}},
],
}
const fourth = {patch: {id: 'another', set: {this: 'that'}}}
const gen = async function* () {
yield first
yield second
yield transaction
yield fourth
}
const it = batchMutations(
gen(),
[first, second, transaction, fourth].reduce((l, m) => l + byteLength(m), 0),
)
expect(await it.next()).toEqual({done: false, value: {mutations: [first, second]}})
expect(await it.next()).toEqual({done: false, value: transaction})
expect(await it.next()).toEqual({done: false, value: {mutations: [fourth]}})
expect(await it.next()).toEqual({done: true, value: undefined})
})