Skip to content

Commit

Permalink
feat: add caching utils
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasKruckenberg committed Mar 15, 2021
1 parent 70faceb commit 2cc2d90
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 0 deletions.
114 changes: 114 additions & 0 deletions packages/core/src/__tests__/cache.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { has, get, info, remove, generateKey } from '../cache'
import mock from 'mock-fs'

describe('cache', () => {
afterAll(() => {
mock.restore()
})

describe('has', () => {
it('returns true if file is present', async () => {
mock({
'/cache': {
'test.png': 'foobar'
}
})

expect(await has('/cache', 'test.png')).toBeTruthy()
})

it('returns false if the file is missing', async () => {
mock({})

expect(await has('/cache', 'test.png')).toBeFalsy()
})
})

describe('get', () => {
it('returns the data', async () => {
mock({
'/cache': {
'test.png': Buffer.from('foobar')
}
})

const res = await get('/cache', 'test.png')
expect(res).toHaveProperty('data', Buffer.from('foobar'))
})

it('returns the metadata if metadata file is present', async () => {
mock({
'/cache': {
'test.png': Buffer.from('foobar'),
'test.png.json': JSON.stringify({ foo: 'bar' })
}
})

const res = await get('/cache', 'test.png')

expect(res).toHaveProperty('data', Buffer.from('foobar'))
expect(res).toHaveProperty('metadata', { foo: 'bar' })
})

it('returns an empty object if metadata file is missing', async () => {
mock({
'/cache': {
'test.png': Buffer.from('foobar')
}
})

const res = await get('/cache', 'test.png')

expect(res).toHaveProperty('data', Buffer.from('foobar'))
expect(res).toHaveProperty('metadata', {})
})

it('throws if no image is found', async (done) => {
mock({})

try {
await get('/cache', 'test.png')
fail()
} catch {
done()
}
})
})

describe('info', () => {
it('returns an object if metadata file is present', async () => {
mock({
'/cache': {
'test.png.json': JSON.stringify({ foo: 'bar' })
}
})

const res = await info('/cache', 'test.png')

expect(res).toHaveProperty('foo', 'bar')
})

it('throws if not metadata file is found', async (done) => {
mock({})

try {
await info('/cache', 'test.png')
fail()
} catch {
done()
}
})
})

describe('remove', () => {
it('removes the image file', () => { })
it('removes the metadata file if present', () => { })
it('throws if no image is found', () => { })
})

describe('generateKey', () => {
it('returns a string', () => { })
test('returned string has file ending', () => { })
test('returned file ending matches config', () => { })
})
})
48 changes: 48 additions & 0 deletions packages/core/src/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { mkdir, readFile, writeFile, stat, unlink } from 'fs/promises'
import { join, extname } from 'path'

export async function has(cachePath: string, key: string): Promise<boolean> {
try {
const file = await stat(join(cachePath, key))
return file.isFile()
} catch {
return false
}
}

export async function get(cachePath: string, key: string): Promise<{ data: Uint8Array, metadata: Record<string, any> }> {
const [data, metadata] = await Promise.all([
readFile(join(cachePath, key)),
has(cachePath, key + '.json').then(has => has ? info(cachePath, key) : {})
])

return { data, metadata }
}

export async function info(cachePath: string, key: string): Promise<Record<string, any>> {
const rawMeta = await readFile(join(cachePath, key + '.json'), 'utf-8')
return JSON.parse(rawMeta)
}

export async function put(cachePath: string, key: string, data: Uint8Array, metadata?: Record<string, any>): Promise<void> {
await mkdir(cachePath, { recursive: true })

await Promise.all([
writeFile(join(cachePath, key), data),
metadata ? writeFile(join(cachePath, key + '.json'), JSON.stringify(metadata)) : undefined
])
}

export async function remove(cachePath: string, key: string): Promise<void> {
await Promise.all([
unlink(join(cachePath, key)),
has(cachePath, key + '.json').then(has => has ? unlink(join(cachePath, key + '.json')) : undefined)
])
}

export function generateKey(url: URL, config: Record<string, any>) {
const name = Buffer.from(JSON.stringify(config)).toString('base64')
const ext = config.format ? `.${config.format}` : extname(url.pathname)

return name + ext
}

0 comments on commit 2cc2d90

Please sign in to comment.