import { computed } from '@wovin/core/mobx' import { filterAndMap, lastWriteWins, query } from '@wovin/core/query' import { rollingFilter } from '@wovin/core/thread' import { Logger } from 'besonders-logger' import { describe, expect, it, vi } from 'vitest' import './test/test-utils.js' const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.DEBUG) // eslint-disable-line unused-imports/no-unused-vars describe('applog-reactive', () => { it('filterAndMap skip computation if query result doesn\'t change', async ({ db, autorunAndReturn, insert }) => { const movies = filterAndMap(db, { at: 'movie/year', vl: 1992 }, { en: 'movieID' }) const fn = vi.fn() autorunAndReturn(() => { DEBUG(`follow-up computed, should only run when changed`, [...movies]) fn() }) insert([ { en: '1111', at: 'movie/year', vl: 1970 }, ]) expect(fn).toHaveBeenCalledTimes(1) insert([ { en: '1234', at: 'movie/year', vl: 1992 }, ]) expect(fn).toHaveBeenCalledTimes(2) }) it('reactive arnold', async ({ db, autorunAndReturn, insert }) => { const directors = computed(() => { return query(db, [ { en: '?arnoldId', at: 'person/name', vl: 'Arnold Schwarzenegger' }, { en: '?movieId', at: 'movie/cast', vl: '?arnoldId' }, // any ?dingdongs, aka vars that are in the previous result/candidate { en: '?movieId', at: 'movie/title', vl: '?movieTitle' }, { en: '?movieId', at: 'movie/director', vl: '?directorId' }, { en: '?directorId', at: 'person/name', vl: '?directorName' }, ], {}).records }) const result = autorunAndReturn(() => directors.get()) expect(result()).to.have.deep.members([ { arnoldId: '101', directorId: '100', directorName: 'James Cameron', movieId: '200', movieTitle: 'The Terminator' }, { arnoldId: '101', directorId: '108', directorName: 'John McTiernan', movieId: '202', movieTitle: 'Predator' }, { arnoldId: '101', directorId: '119', directorName: 'Mark L. Lester', movieId: '205', movieTitle: 'Commando' }, { arnoldId: '101', directorId: '100', directorName: 'James Cameron', movieId: '207', movieTitle: 'Terminator 2: Judgment Day' }, { arnoldId: '101', directorId: '127', directorName: 'Jonathan Mostow', movieId: '208', movieTitle: 'Terminator 3: Rise of the Machines', }, ]) const fn = vi.fn() autorunAndReturn(() => { DEBUG(`follow-up computed, shouldn't run when not changed`, directors.get()) fn() }) DEBUG(`------------ inserting irrelevant ---------------`) insert([ { en: '213', at: 'movie/cast', vl: '999' }, ]) expect(fn).toHaveBeenCalledTimes(1) DEBUG(`------------ inserting Arnold into Lethal Weapon --------------`) insert([ { en: '213', at: 'movie/cast', vl: '101' }, ]) expect(result()).to.have.deep.members([ { arnoldId: '101', directorId: '100', directorName: 'James Cameron', movieId: '200', movieTitle: 'The Terminator' }, { arnoldId: '101', directorId: '108', directorName: 'John McTiernan', movieId: '202', movieTitle: 'Predator' }, { arnoldId: '101', directorId: '119', directorName: 'Mark L. Lester', movieId: '205', movieTitle: 'Commando' }, { arnoldId: '101', directorId: '100', directorName: 'James Cameron', movieId: '207', movieTitle: 'Terminator 2: Judgment Day' }, { arnoldId: '101', directorId: '127', directorName: 'Jonathan Mostow', movieId: '208', movieTitle: 'Terminator 3: Rise of the Machines', }, { arnoldId: '101', directorId: '111', directorName: 'Richard Donner', movieId: '213', movieTitle: 'Lethal Weapon 3' }, ]) expect(fn).toHaveBeenCalledTimes(2) }) it('double arnold', async ({ db, autorunAndReturn, insert }) => { const directorsName = computed(() => { return query(db, [ { en: '?arnoldId', at: 'person/name', vl: 'Arnold Schwarzenegger' }, { en: '?movieId', at: 'movie/cast', vl: '?arnoldId' }, // any ?dingdongs, aka vars that are in the previous result/candidate { en: '?movieId', at: 'movie/title', vl: '?movieTitle' }, { en: '?movieId', at: 'movie/director', vl: '?directorId' }, { en: '?directorId', at: 'person/name', vl: '?directorName' }, ], {}).records }) const directorsBorn = computed(() => { return query(db, [ { en: '?arnoldId', at: 'person/name', vl: 'Arnold Schwarzenegger' }, { en: '?movieId', at: 'movie/cast', vl: '?arnoldId' }, // any ?dingdongs, aka vars that are in the previous result/candidate { en: '?movieId', at: 'movie/title', vl: '?movieTitle' }, { en: '?movieId', at: 'movie/director', vl: '?directorId' }, { en: '?directorId', at: 'person/born', vl: '?directorBorn' }, ], {}).records }) const fn = vi.fn() autorunAndReturn(() => { DEBUG(`RESULT changed`, { names: directorsName.get(), born: directorsBorn.get() }) fn() }) DEBUG(`------------ inserting irrelevant ---------------`) insert([ { en: '213', at: 'movie/cast', vl: '999' }, ]) expect(fn).toHaveBeenCalledTimes(1) DEBUG(`------------ inserting Arnold into Lethal Weapon ---------------`) insert([ { en: '213', at: 'movie/cast', vl: '101' }, ]) expect(fn).toHaveBeenCalledTimes(2) }) it('rollingFilter update cached', async ({ db, insert, autorunAndReturn }) => { const filteredLogs = rollingFilter(db, { at: 'movie/year', vl: 1992 }) const fn = vi.fn() autorunAndReturn(() => { const logs = [...filteredLogs.applogs] DEBUG(`Observing filteredLogs`, logs) fn(logs) }) // Insert a log that doesn't match the filter DEBUG(`------------ inserting irrelevant ---------------`) insert([ { en: '1234', at: 'movie/year', vl: 1970 }, ]) expect(fn).toHaveBeenCalledTimes(1) expect(fn).toHaveBeenCalledWith(expect.toBeApplogs([ { at: 'movie/year', en: '213', vl: 1992 }, ])) DEBUG(`------------ inserting Arnold into Lethal Weapon ---------------`) insert([ { en: '1235', at: 'movie/year', vl: 1992 }, ]) expect(fn).toHaveBeenCalledTimes(2) expect(fn.mock.calls[1][0]).toEqual(expect.toBeApplogs([ { en: '213', at: 'movie/year', vl: 1992 }, { en: '1235', at: 'movie/year', vl: 1992 }, ])) }) it('lastWriteWins', async ({ db, insert, autorunAndReturn }) => { const filteredLogs = rollingFilter(lastWriteWins(db), { at: 'movie/year', vl: 1992 }) const fn = vi.fn() autorunAndReturn(() => { const logs = [...filteredLogs.applogs] DEBUG(`Observing filteredLogs`, logs) fn(logs) }) // Insert a log that doesn't match the filter DEBUG(`------------ inserting irrelevant ---------------`) insert([ { en: '1234', at: 'movie/year', vl: 1970 }, ]) expect(fn).toHaveBeenCalledTimes(1) expect(fn).toHaveBeenCalledWith(expect.toBeApplogs([ { at: 'movie/year', en: '213', vl: 1992 }, ])) expect(fn.mock.calls[0][0]).toEqual(expect.toBeApplogs([ { at: 'movie/year', en: '213', vl: 1992 }, ])) DEBUG(`------------ inserting Arnold into Lethal Weapon ---------------`) insert([ { en: '1235', at: 'movie/year', vl: 1992 }, ]) expect(fn).toHaveBeenCalledTimes(2) expect(fn.mock.calls[1][0]).toEqual(expect.toBeApplogs([ { en: '213', at: 'movie/year', vl: 1992 }, { en: '1235', at: 'movie/year', vl: 1992 }, ])) }) })