Tldraw/packages/tlstore/src/lib/test/recordStoreQueries.test.ts

824 wiersze
24 KiB
TypeScript

import { atom, RESET_VALUE } from 'signia'
import { BaseRecord, ID } from '../BaseRecord'
import { createRecordType } from '../RecordType'
import { Store } from '../Store'
import { StoreSchema } from '../StoreSchema'
interface Author extends BaseRecord<'author'> {
name: string
age: number
}
const Author = createRecordType<Author>('author', {
validator: {
validate(value) {
const author = value as Author
if (author.typeName !== 'author') throw Error()
if (!author.id.startsWith('author:')) throw Error()
if (!Number.isFinite(author.age)) throw Error()
if (author.age < 0) throw Error()
return author
},
},
scope: 'document',
}).withDefaultProperties(() => ({ age: 23 }))
interface Book extends BaseRecord<'book'> {
title: string
authorId: ID<Author>
}
const Book = createRecordType<Book>('book', {
validator: {
validate(value) {
const book = value as Book
if (!book.id.startsWith('book:')) throw Error()
if (book.typeName !== 'book') throw Error()
if (typeof book.title !== 'string') throw Error()
if (!book.authorId.startsWith('author')) throw Error()
return book
},
},
scope: 'document',
})
const authors = {
tolkein: Author.create({ name: 'J.R.R. Tolkein' }),
bradbury: Author.create({ name: 'Ray Bradbury' }),
davidMitchellSerious: Author.create({ name: 'David Mitchell' }),
davidMitchellFunny: Author.create({ name: 'David Mitchell' }),
}
const books = {
cloudAtlas: Book.create({ title: 'Cloud Atlas', authorId: authors.davidMitchellSerious.id }),
myLifeInComedy: Book.create({
title: 'My Life in Comedy',
authorId: authors.davidMitchellFunny.id,
}),
lotr: Book.create({ title: 'Lord of the Rings', authorId: authors.tolkein.id }),
farenheit: Book.create({ title: 'Farenheit 451', authorId: authors.bradbury.id }),
}
let store: Store<Author | Book>
beforeEach(() => {
store = new Store({
props: {},
schema: StoreSchema.create<Author | Book>(
{
author: Author,
book: Book,
},
{
snapshotMigrations: {
currentVersion: 0,
firstVersion: 0,
migrators: {},
},
}
),
})
store.put([
authors.tolkein,
authors.bradbury,
books.lotr,
books.farenheit,
authors.davidMitchellFunny,
authors.davidMitchellSerious,
books.cloudAtlas,
books.myLifeInComedy,
])
})
describe('indexes', () => {
it('are cached', () => {
const authorNameIndex1 = store.query.index('author', 'name')
const authorNameIndex2 = store.query.index('author', 'name')
expect(authorNameIndex1).toBe(authorNameIndex2)
})
it('can be made on any property', () => {
const authorNameIndex = store.query.index('author', 'name')
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
expect(authorNameIndex.value.get('David Mitchell')).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
const bookTitleIndex = store.query.index('book', 'title')
expect(bookTitleIndex.value.get('Cloud Atlas')).toEqual(new Set([books.cloudAtlas.id]))
expect(bookTitleIndex.value.get('Lord of the Rings')).toEqual(new Set([books.lotr.id]))
})
it('can have things added when records are added', () => {
const authorNameIndex = store.query.index('author', 'name')
// deref to make it compute once
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
const newAuthor = Author.create({ name: 'New Author' })
store.put([newAuthor])
expect(authorNameIndex.value.get('New Author')).toEqual(new Set([newAuthor.id]))
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff === RESET_VALUE) throw new Error('should not be reset')
expect(diff).toHaveLength(1)
expect(diff[0].get('New Author')).toEqual({
added: new Set([newAuthor.id]),
})
expect(diff[0].size).toBe(1)
const moreNewAuthors = [
Author.create({ name: 'New Author' }),
Author.create({ name: 'New Author' }),
Author.create({ name: 'New Author' }),
]
lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.put(moreNewAuthors)
expect(authorNameIndex.value.get('New Author')).toEqual(
new Set([newAuthor.id, ...moreNewAuthors.map((a) => a.id)])
)
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff2 === RESET_VALUE) throw new Error('should not be reset')
expect(diff2).toHaveLength(1)
expect(diff2[0].get('New Author')).toEqual({ added: new Set(moreNewAuthors.map((a) => a.id)) })
})
it('can have things added when records are updated', () => {
const authorNameIndex = store.query.index('author', 'name')
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.put([{ ...authors.bradbury, name: 'J.R.R. Tolkein' }])
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(
new Set([authors.tolkein.id, authors.bradbury.id])
)
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff === RESET_VALUE) throw new Error('should not be reset')
expect(diff).toHaveLength(1)
expect(diff[0].size).toBe(2)
expect(diff[0].get('J.R.R. Tolkein')).toEqual({
added: new Set([authors.bradbury.id]),
})
expect(diff[0].get('Ray Bradbury')).toEqual({
removed: new Set([authors.bradbury.id]),
})
lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.put([
{ ...authors.davidMitchellFunny, name: 'J.R.R. Tolkein' },
{ ...authors.davidMitchellSerious, name: 'J.R.R. Tolkein' },
])
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(
new Set([
authors.tolkein.id,
authors.bradbury.id,
authors.davidMitchellFunny.id,
authors.davidMitchellSerious.id,
])
)
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff2 === RESET_VALUE) throw new Error('should not be reset')
expect(diff2).toHaveLength(1)
expect(diff2[0].size).toBe(2)
expect(diff2[0].get('J.R.R. Tolkein')).toEqual({
added: new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id]),
})
expect(diff2[0].get('David Mitchell')).toEqual({
removed: new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id]),
})
})
it('can have things removed when records are removed', () => {
const authorNameIndex = store.query.index('author', 'name')
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.remove([authors.tolkein.id])
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(undefined)
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff === RESET_VALUE) throw new Error('should not be reset')
expect(diff).toHaveLength(1)
expect(diff[0].size).toBe(1)
expect(diff[0].get('J.R.R. Tolkein')).toEqual({
removed: new Set([authors.tolkein.id]),
})
lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.remove([
authors.bradbury.id,
authors.davidMitchellFunny.id,
authors.davidMitchellSerious.id,
])
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(undefined)
expect(authorNameIndex.value.get('David Mitchell')).toEqual(undefined)
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff2 === RESET_VALUE) throw new Error('should not be reset')
expect(diff2).toHaveLength(1)
expect(diff2[0].size).toBe(2)
expect(diff2[0].get('Ray Bradbury')).toEqual({
removed: new Set([authors.bradbury.id]),
})
expect(diff2[0].get('David Mitchell')).toEqual({
removed: new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id]),
})
})
it('can have things removed when records are updated', () => {
const authorNameIndex = store.query.index('author', 'name')
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.put([{ ...authors.tolkein, name: 'Ray Bradbury' }])
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(
new Set([authors.tolkein.id, authors.bradbury.id])
)
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(undefined)
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff === RESET_VALUE) throw new Error('should not be reset')
expect(diff).toHaveLength(1)
expect(diff[0].size).toBe(2)
expect(diff[0].get('J.R.R. Tolkein')).toEqual({
removed: new Set([authors.tolkein.id]),
})
expect(diff[0].get('Ray Bradbury')).toEqual({
added: new Set([authors.tolkein.id]),
})
lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.put([
{ ...authors.davidMitchellFunny, name: 'Ray Bradbury' },
{ ...authors.davidMitchellSerious, name: 'Ray Bradbury' },
])
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(
new Set([
authors.tolkein.id,
authors.bradbury.id,
authors.davidMitchellFunny.id,
authors.davidMitchellSerious.id,
])
)
expect(authorNameIndex.value.get('David Mitchell')).toEqual(undefined)
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff2 === RESET_VALUE) throw new Error('should not be reset')
expect(diff2).toHaveLength(1)
expect(diff2[0].size).toBe(2)
expect(diff2[0].get('David Mitchell')).toEqual({
removed: new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id]),
})
expect(diff2[0].get('Ray Bradbury')).toEqual({
added: new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id]),
})
})
it('handles things being removed and added for the same value at the same time', () => {
const authorNameIndex = store.query.index('author', 'name')
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
let lastChangedEpoch = authorNameIndex.lastChangedEpoch
// do remove first
store.remove([authors.tolkein.id])
const newAuthor = Author.create({ name: 'J.R.R. Tolkein' })
store.put([newAuthor])
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([newAuthor.id]))
const diff = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff === RESET_VALUE) throw new Error('should not be reset')
expect(diff).toHaveLength(1)
expect(diff[0].size).toBe(1)
expect(diff[0].get('J.R.R. Tolkein')).toEqual({
removed: new Set([authors.tolkein.id]),
added: new Set([newAuthor.id]),
})
lastChangedEpoch = authorNameIndex.lastChangedEpoch
// do updates
store.put([{ ...authors.davidMitchellFunny, name: 'Ray Bradbury' }])
store.put([{ ...authors.bradbury, name: 'David Mitchell' }])
expect(authorNameIndex.value.get('Ray Bradbury')).toEqual(
new Set([authors.davidMitchellFunny.id])
)
expect(authorNameIndex.value.get('David Mitchell')).toEqual(
new Set([authors.bradbury.id, authors.davidMitchellSerious.id])
)
const diff2 = authorNameIndex.getDiffSince(lastChangedEpoch)
if (diff2 === RESET_VALUE) throw new Error('should not be reset')
expect(diff2).toHaveLength(1)
expect(diff2[0].size).toBe(2)
expect(diff2[0].get('Ray Bradbury')).toEqual({
added: new Set([authors.davidMitchellFunny.id]),
removed: new Set([authors.bradbury.id]),
})
expect(diff2[0].get('David Mitchell')).toEqual({
added: new Set([authors.bradbury.id]),
removed: new Set([authors.davidMitchellFunny.id]),
})
})
it('has the same value if nothing changed', () => {
const authorNameIndex = store.query.index('author', 'name')
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
const lastChangedEpoch = authorNameIndex.lastChangedEpoch
store.put([{ ...authors.tolkein, age: 23 }])
expect(authorNameIndex.value.get('J.R.R. Tolkein')).toEqual(new Set([authors.tolkein.id]))
expect(lastChangedEpoch).toBe(authorNameIndex.lastChangedEpoch)
})
})
describe('queries for ids', () => {
it('can query for all values of a given type', () => {
const bookQuery = store.query.ids('book')
expect(bookQuery.value).toEqual(
new Set([books.cloudAtlas.id, books.farenheit.id, books.lotr.id, books.myLifeInComedy.id])
)
const authorQuery = store.query.ids('author')
expect(authorQuery.value).toEqual(
new Set([
authors.bradbury.id,
authors.davidMitchellFunny.id,
authors.davidMitchellSerious.id,
authors.tolkein.id,
])
)
const newAuthor = Author.create({ name: 'J.R.R. Tolkein' })
const newBook = Book.create({ title: 'The Hobbit', authorId: newAuthor.id })
store.put([newAuthor, newBook])
expect(bookQuery.value).toEqual(
new Set([
books.cloudAtlas.id,
books.farenheit.id,
books.lotr.id,
books.myLifeInComedy.id,
newBook.id,
])
)
expect(authorQuery.value).toEqual(
new Set([
authors.bradbury.id,
authors.davidMitchellFunny.id,
authors.davidMitchellSerious.id,
authors.tolkein.id,
newAuthor.id,
])
)
})
it('can query for a single value', () => {
const jrr = store.query.ids('author', () => ({
name: { eq: 'J.R.R. Tolkein' },
}))
expect(jrr.value).toEqual(new Set([authors.tolkein.id]))
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
})
it('can query for multiple values', () => {
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
const mitchell30 = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
age: { eq: 30 },
}))
expect(mitchell30.value).toEqual(new Set([authors.davidMitchellFunny.id]))
})
it('can use a reactive query', () => {
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
const currentAuthor = atom('currentAuthor', 'David Mitchell')
const currentAge = atom('currentAge', 30)
const mitchell30 = store.query.ids('author', () => ({
name: { eq: currentAuthor.value },
age: { eq: currentAge.value },
}))
expect(mitchell30.value).toEqual(new Set([authors.davidMitchellFunny.id]))
let lastChangedEpoch = mitchell30.lastChangedEpoch
currentAge.set(23)
expect(mitchell30.value).toEqual(new Set([authors.davidMitchellSerious.id]))
const diff = mitchell30.getDiffSince(lastChangedEpoch)
if (diff === RESET_VALUE) throw new Error('should not be reset')
expect(diff).toHaveLength(1)
expect(diff[0]).toEqual({
added: new Set([authors.davidMitchellSerious.id]),
removed: new Set([authors.davidMitchellFunny.id]),
})
currentAuthor.set('J.R.R. Tolkein')
lastChangedEpoch = mitchell30.lastChangedEpoch
expect(mitchell30.value).toEqual(new Set([authors.tolkein.id]))
const diff2 = mitchell30.getDiffSince(lastChangedEpoch)
if (diff2 === RESET_VALUE) throw new Error('should not be reset')
expect(diff2).toHaveLength(1)
expect(diff2[0]).toEqual({
added: new Set([authors.tolkein.id]),
removed: new Set([authors.davidMitchellSerious.id]),
})
})
it('supports not-equals matches', () => {
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
const mitchell = store.query.ids('author', () => ({
name: { neq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(new Set([authors.tolkein.id, authors.bradbury.id]))
const ageNot23 = store.query.ids('author', () => ({
age: { neq: 23 },
}))
expect(ageNot23.value).toEqual(new Set([authors.davidMitchellFunny.id]))
})
it('supports records being added', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
const newAuthor = Author.create({ name: 'David Mitchell' })
store.put([newAuthor])
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id, newAuthor.id])
)
})
it('supports records being removed', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
store.remove([authors.davidMitchellFunny.id])
expect(mitchell.value).toEqual(new Set([authors.davidMitchellSerious.id]))
})
it('supports records being updated', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
age: { neq: 30 },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
expect(mitchell.value).toEqual(new Set([authors.davidMitchellSerious.id]))
store.put([{ ...authors.davidMitchellFunny, age: 23 }])
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellSerious.id, authors.davidMitchellFunny.id])
)
})
it('does not update if unrelated records are added, upated, or removed', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
const lastChangedEpoch = mitchell.lastChangedEpoch
const newAuthor = Author.create({ name: 'William Shakespeare' })
store.put([newAuthor])
mitchell.value
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
store.remove([authors.tolkein.id])
mitchell.value
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
})
it('doesnt change if related records are updated', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
const lastChangedEpoch = mitchell.lastChangedEpoch
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
mitchell.value
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
// make a change that does affect the query just to check
store.put([{ ...authors.davidMitchellFunny, name: 'steve' }])
mitchell.value
expect(mitchell.lastChangedEpoch).toBeGreaterThan(lastChangedEpoch)
})
it('supports items being removed and then added back', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
const lastChangedEpoch = mitchell.lastChangedEpoch
store.remove([authors.davidMitchellFunny.id])
store.put([authors.davidMitchellFunny])
mitchell.value
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
})
it('supports items being added and then removed', () => {
const mitchell = store.query.ids('author', () => ({
name: { eq: 'David Mitchell' },
}))
expect(mitchell.value).toEqual(
new Set([authors.davidMitchellFunny.id, authors.davidMitchellSerious.id])
)
const lastChangedEpoch = mitchell.lastChangedEpoch
const newMitchell = Author.create({ name: 'David Mitchell' })
store.put([newMitchell])
store.remove([newMitchell.id])
mitchell.value
expect(mitchell.lastChangedEpoch).toEqual(lastChangedEpoch)
})
})
const bookComparator = (a: Book, b: Book) => a.title.localeCompare(b.title)
describe('queries for records', () => {
it('can query for all values of a given type', () => {
const allBooks = store.query.records('book')
expect(allBooks.value.sort(bookComparator)).toEqual(
[books.cloudAtlas, books.farenheit, books.lotr, books.myLifeInComedy].sort(bookComparator)
)
const newBook = Book.create({ title: 'The Hobbit', authorId: authors.tolkein.id })
store.put([newBook])
expect(allBooks.value.sort(bookComparator)).toEqual(
[books.cloudAtlas, books.farenheit, books.lotr, books.myLifeInComedy, newBook].sort(
bookComparator
)
)
})
it('can query for a single value', () => {
const farenheit = store.query.records('book', () => ({
title: { eq: 'Farenheit 451' },
}))
expect(farenheit.value).toEqual([books.farenheit])
})
it('can query for multiple values', () => {
const funnyGuide = Book.create({
title: 'How to be a funny man',
authorId: authors.davidMitchellFunny.id,
})
store.put([funnyGuide])
const mitchell = store.query.records('book', () => ({
authorId: { eq: authors.davidMitchellFunny.id },
}))
expect(mitchell.value.sort(bookComparator)).toEqual(
[books.myLifeInComedy, funnyGuide].sort(bookComparator)
)
})
it('supports reactive queries', () => {
const currentAuthor = atom('currentAuthor', authors.davidMitchellFunny.id)
const booksQuery = store.query.records('book', () => ({
authorId: { eq: currentAuthor.value },
}))
expect(booksQuery.value).toEqual([books.myLifeInComedy])
currentAuthor.set(authors.tolkein.id)
expect(booksQuery.value).toEqual([books.lotr])
})
})
describe('filtering history', () => {
it('caches filters', () => {
const filter = store.query.filterHistory('author')
const filter2 = store.query.filterHistory('author')
expect(filter).toBe(filter2)
})
it('allows filtering history', () => {
const authorHistory = store.query.filterHistory('author')
authorHistory.value
let lastChangedEpoch = authorHistory.lastChangedEpoch
expect(authorHistory.getDiffSince(lastChangedEpoch - 1)).toBe(RESET_VALUE)
// updating an author should change the history
store.put([{ ...authors.davidMitchellFunny, age: 30 }])
authorHistory.value
expect(lastChangedEpoch).toBeLessThan(authorHistory.lastChangedEpoch)
expect(authorHistory.getDiffSince(lastChangedEpoch)).toMatchObject([
{ updated: { [authors.davidMitchellFunny.id]: [{ age: 23 }, { age: 30 }] } },
])
lastChangedEpoch = authorHistory.lastChangedEpoch
// updating a book should not change the history
store.put([
{ ...books.lotr, title: 'The Lord of the Rings Part I: The Fellowship of the Ring' },
])
authorHistory.value
expect(authorHistory.lastChangedEpoch).toEqual(lastChangedEpoch)
expect(authorHistory.getDiffSince(lastChangedEpoch)).toMatchObject([])
})
it('should not update if changes in a window of time cancel each other out', () => {
const authorHistory = store.query.filterHistory('author')
const epoch = authorHistory.value
const newAuthor = Author.create({ name: 'Stanley Briggs' })
store.put([newAuthor])
store.put([{ ...newAuthor, age: 38 }])
store.remove([newAuthor.id])
expect(authorHistory.value).toEqual(epoch)
store.remove([authors.tolkein.id])
store.put([authors.tolkein])
expect(authorHistory.value).toEqual(epoch)
})
it('removes update entries if a thing was deleted', () => {
const authorHistory = store.query.filterHistory('author')
authorHistory.value
const lastChangedEpoch = authorHistory.lastChangedEpoch
store.put([{ ...authors.davidMitchellFunny, age: 38 }])
store.put([{ ...authors.davidMitchellFunny, age: 343 }])
store.remove([authors.davidMitchellFunny.id])
expect(authorHistory.getDiffSince(lastChangedEpoch)).toMatchObject([
{
// shows the original, not the updated version
removed: { [authors.davidMitchellFunny.id]: { age: 23 } },
},
])
})
it('collapses multiple updated entries into one', () => {
const authorHistory = store.query.filterHistory('author')
authorHistory.value
const lastChangedEpoch = authorHistory.lastChangedEpoch
store.put([{ ...authors.davidMitchellFunny, age: 38 }])
store.put([{ ...authors.davidMitchellFunny, age: 343 }])
expect(authorHistory.getDiffSince(lastChangedEpoch)).toMatchObject([
{
updated: { [authors.davidMitchellFunny.id]: [{ age: 23 }, { age: 343 }] },
},
])
})
it('collapeses an add + update entry into just an add entry', () => {
const authorHistory = store.query.filterHistory('author')
authorHistory.value
const lastChangedEpoch = authorHistory.lastChangedEpoch
const newAuthor = Author.create({ name: 'Stanley Briggs' })
store.put([newAuthor])
store.put([{ ...newAuthor, age: 38 }])
expect(authorHistory.getDiffSince(lastChangedEpoch)).toMatchObject([
{
added: { [newAuthor.id]: { age: 38 } },
},
])
})
})