budibase/packages/core/test/memory.js

179 lines
5.7 KiB
JavaScript

import { isUndefined, has } from "lodash"
import { take } from "lodash/fp"
import { Readable, Writable } from "readable-stream"
import { Buffer } from "safe-buffer"
import { splitKey, joinKey, $, keySep, getFileFromKey } from "../src/common"
import { getLastPartInKey } from "../src/templateApi/hierarchy"
const folderMarker = "OH-YES-ITSA-FOLDER-"
const isFolder = val => {
if (isUndefined(val)) {
throw new Error("Passed undefined value for folder")
}
return val.includes(folderMarker)
}
const getParentFolderKey = key =>
$(key, [splitKey, take(splitKey(key).length - 1), joinKey])
const getParentFolder = (data, key) => {
if (key === keySep) return null
const parentKey = getParentFolderKey(key)
if (parentKey === keySep) return null
if (data[parentKey] === undefined)
throw new Error(
"Parent folder for " + key + " does not exist (" + parentKey + ")"
)
return JSON.parse(data[parentKey])
}
const addItemToParentFolder = (data, path) => {
if (getParentFolderKey(path) === "/") return
const parentFolder = getParentFolder(data, path)
parentFolder.items.push(getLastPartInKey(path))
data[getParentFolderKey(path)] = JSON.stringify(parentFolder)
}
export const createFile = data => async (path, content) => {
if (await exists(data)(path)) {
throw new Error(path + " already exists")
}
addItemToParentFolder(data, path)
data[path] = content
}
export const updateFile = data => async (path, content) => {
// putting this check in to force use of create
if (!(await exists(data)(path))) {
throw new Error("cannot update " + path + " - does not exist")
}
data[path] = content
}
export const writableFileStream = data => async path => {
//if(!await exists(data)(path)) throw new Error("cannot write stream to " + path + " - does not exist");
if (!getParentFolder(data, path)) {
throw new Error("Parent folder for " + path + " does not exist")
}
const stream = Writable()
stream._write = (chunk, encoding, done) => {
data[path] = data[path] === undefined ? [] : data[path]
data[path] = [...data[path], ...chunk]
done()
}
addItemToParentFolder(data, path)
return stream
}
export const readableFileStream = data => async path => {
if (!(await exists(data)(path)))
throw new Error("cannot read stream from " + path + " - does not exist")
const s = new Readable()
s._read = () => {
s.push(Buffer.from(data[path]))
s.push(null)
}
return s
}
export const getFileSize = data => async path => {
if (!(await exists(data)(path)))
throw new Error("cannot get size of " + path + " - does not exist")
return data[path].length
}
export const renameFile = data => async (oldKey, newKey) => {
if (!(await exists(data)(oldKey)))
throw new Error("cannot rename path: " + oldKey + " ... does not exist")
if (await exists(data)(newKey))
throw new Error("cannot rename path: " + newKey + " ... already exists")
data[newKey] = data[oldKey]
delete data[oldKey]
const parent = getParentFolder(data, newKey)
const oldFileName = getFileFromKey(oldKey)
const newFileName = getFileFromKey(newKey)
parent.items = [...parent.items.filter(i => i !== oldFileName), newFileName]
data[getParentFolderKey(newKey)] = JSON.stringify(parent)
}
export const loadFile = data => async path => {
const result = data[path]
if (isUndefined(result)) {
throw new Error("Load failed - path " + path + " does not exist")
}
return result
}
export const exists = data => async path => has(data, path)
export const deleteFile = data => async path => {
if (!(await exists(data)(path)))
throw new Error("Cannot delete file, path " + path + " does not exist")
if (isFolder(data[path]))
throw new Error("DeleteFile: Path " + path + " is a folder, not a file")
const parentFolder = getParentFolder(data, path)
parentFolder.items = parentFolder.items.filter(
i => i !== getLastPartInKey(path)
)
data[getParentFolderKey(path)] = JSON.stringify(parentFolder)
delete data[path]
}
export const createFolder = data => async path => {
if (await exists(data)(path))
throw new Error("Cannot create folder, path " + path + " already exists")
addItemToParentFolder(data, path)
data[path] = JSON.stringify({ folderMarker, items: [] })
}
export const deleteFolder = data => async path => {
if (!(await exists(data)(path)))
throw new Error("Cannot delete folder, path " + path + " does not exist")
if (!isFolder(data[path]))
throw new Error("DeleteFolder: Path " + path + " is not a folder")
for (let item of JSON.parse(data[path]).items) {
const fullItemPath = `${path}/${item}`
if (isFolder(data[fullItemPath])) {
await deleteFolder(data)(fullItemPath)
} else {
await deleteFile(data)(fullItemPath)
}
}
const parent = getParentFolder(data, path)
if (parent) {
parent.items = parent.items.filter(f => f !== getLastPartInKey(path))
data[getParentFolderKey(path)] = JSON.stringify(parent)
}
delete data[path]
}
export const getFolderContents = data => async folderPath => {
if (!(await exists(data)(folderPath)))
throw new Error("Folder does not exist: " + folderPath)
if (!isFolder(data[folderPath]))
throw new Error("Not a folder: " + folderPath)
return JSON.parse(data[folderPath]).items
}
export default data => {
return {
createFile: createFile(data),
updateFile: updateFile(data),
loadFile: loadFile(data),
exists: exists(data),
deleteFile: deleteFile(data),
createFolder: createFolder(data),
deleteFolder: deleteFolder(data),
readableFileStream: readableFileStream(data),
writableFileStream: writableFileStream(data),
renameFile: renameFile(data),
getFolderContents: getFolderContents(data),
getFileSize: getFileSize(data),
datastoreType: "memory",
datastoreDescription: "",
data,
}
}