diff --git a/packages/backend-core/src/couch/pouchLike.ts b/packages/backend-core/src/couch/pouchLike.ts index 80ebe1d363..2591380ba0 100644 --- a/packages/backend-core/src/couch/pouchLike.ts +++ b/packages/backend-core/src/couch/pouchLike.ts @@ -2,8 +2,7 @@ import Nano from "nano" import { AnyDocument } from "@budibase/types" import { getCouchInfo } from "./couch" import { directCouchCall } from "./utils" -import { ReadStream, WriteStream } from "fs" -import { dangerousGetDB } from "../db" +import { getPouchDB } from "../db" export type PouchLikeOpts = { skip_setup?: boolean @@ -20,10 +19,6 @@ export type QueryOpts = { keys?: string[] } -export type DumpOpts = { - filter?: (doc: AnyDocument) => boolean -} - export class PouchLike { public readonly name: string private static nano: Nano.ServerScope @@ -32,13 +27,21 @@ export class PouchLike { constructor(dbName: string, opts?: PouchLikeOpts) { this.name = dbName this.pouchOpts = opts || {} + if (!PouchLike.nano) { + PouchLike.init() + } } static init() { const couchInfo = getCouchInfo() - this.nano = Nano({ + PouchLike.nano = Nano({ url: couchInfo.url, - cookie: couchInfo.cookie, + requestDefaults: { + headers: { + Authorization: couchInfo.cookie, + }, + }, + parseUrl: false, }) } @@ -56,16 +59,30 @@ export class PouchLike { return PouchLike.nano.db.use(this.name) } - async info() {} + private async updateOutput(fnc: any) { + try { + return await fnc() + } catch (err: any) { + if (err.statusCode) { + err.status = err.statusCode + } + throw err + } + } + + async info() { + const db = PouchLike.nano.db.use(this.name) + return db.info() + } async get(id: string) { const db = await this.checkSetup() - return await db.get(id) + return this.updateOutput(() => db.get(id)) } async remove(id: string, rev: string) { const db = await this.checkSetup() - return await db.destroy(id, rev) + return this.updateOutput(() => db.destroy(id, rev)) } async put(document: AnyDocument) { @@ -73,23 +90,23 @@ export class PouchLike { throw new Error("Cannot store document without _id field.") } const db = await this.checkSetup() - return await db.insert(document) + return this.updateOutput(() => db.insert(document)) } async bulkDocs(documents: AnyDocument[]) { const db = await this.checkSetup() - return await db.bulk({ docs: documents }) + return this.updateOutput(() => db.bulk({ docs: documents })) } async allDocs(params: QueryOpts) { const db = await this.checkSetup() - return await db.fetch({ keys: [] }, params) + return this.updateOutput(() => db.list(params)) } async query(viewName: string, params: QueryOpts) { const db = await this.checkSetup() const [database, view] = viewName.split("/") - return await db.view(database, view, params) + return this.updateOutput(() => db.view(database, view, params)) } async destroy() { @@ -97,37 +114,47 @@ export class PouchLike { await PouchLike.nano.db.destroy(this.name) } catch (err: any) { // didn't exist, don't worry - if (err.status === 404) { + if (err.statusCode === 404) { return } else { - throw err + throw { ...err, status: err.statusCode } } } } async compact() { const db = await this.checkSetup() - return await db.compact() + return this.updateOutput(() => db.compact()) } - // utilise PouchDB for this - async dump(stream: WriteStream, params: DumpOpts) { - const pouch = dangerousGetDB(this.name) - // @ts-ignore - return pouch.dump(stream, params) + private doWithPouchDB(func: string) { + const dbName = this.name + return async (args: any[]) => { + const pouch = getPouchDB(dbName) + // @ts-ignore + return pouch[func](...args) + } } - // utilise PouchDB for this - async load(stream: ReadStream) { - const pouch = dangerousGetDB(this.name) - // @ts-ignore - return pouch.load(stream) + // All below functions are in-frequently called, just utilise PouchDB + // for them as it implements them better than we can + async dump(...args: any[]) { + return this.doWithPouchDB("dump")(args) } - // pouch specific functions - indexes come from the pouchdb-find library - async createIndex() {} + async load(...args: any[]) { + return this.doWithPouchDB("load")(args) + } - async deleteIndex() {} + async createIndex(...args: any[]) { + return this.doWithPouchDB("createIndex")(args) + } - async getIndexes() {} + async deleteIndex(...args: any[]) { + return this.doWithPouchDB("createIndex")(args) + } + + async getIndexes(...args: any[]) { + return this.doWithPouchDB("createIndex")(args) + } } diff --git a/packages/backend-core/src/db/index.ts b/packages/backend-core/src/db/index.ts index 9f6c097f0d..73d1327af3 100644 --- a/packages/backend-core/src/db/index.ts +++ b/packages/backend-core/src/db/index.ts @@ -2,6 +2,7 @@ import * as pouch from "./pouch" import env from "../environment" import { PouchOptions, CouchFindOptions } from "@budibase/types" import PouchDB from "pouchdb" +import { PouchLike } from "../couch" import { directCouchQuery } from "../couch" export { directCouchQuery } from "../couch" @@ -38,10 +39,7 @@ export async function init(opts?: PouchOptions) { initialised = true } -// NOTE: THIS IS A DANGEROUS FUNCTION - USE WITH CAUTION -// this function is prone to leaks, should only be used -// in situations that using the function doWithDB does not work -export function dangerousGetDB(dbName: string, opts?: any): PouchDB.Database { +export function getPouchDB(dbName: string, opts?: any): PouchDB.Database { checkInitialised() if (env.isTest()) { dbList.add(dbName) @@ -55,6 +53,13 @@ export function dangerousGetDB(dbName: string, opts?: any): PouchDB.Database { return db } +// NOTE: THIS IS A DANGEROUS FUNCTION - USE WITH CAUTION +// this function is prone to leaks, should only be used +// in situations that using the function doWithDB does not work +export function dangerousGetDB(dbName: string, opts?: any): PouchLike { + return new PouchLike(dbName, opts) +} + // use this function if you have called dangerousGetDB - close // the databases you've opened once finished export async function closeDB(db: PouchDB.Database) { @@ -79,11 +84,7 @@ export async function doWithDB(dbName: string, cb: any, opts = {}) { const db = dangerousGetDB(dbName, opts) // need this to be async so that we can correctly close DB after all // async operations have been completed - try { - return await cb(db) - } finally { - await closeDB(db) - } + return await cb(db) } export function allDbs() { diff --git a/packages/backend-core/src/db/pouch.ts b/packages/backend-core/src/db/pouch.ts index 6eca07e0cd..fdb051060a 100644 --- a/packages/backend-core/src/db/pouch.ts +++ b/packages/backend-core/src/db/pouch.ts @@ -66,7 +66,6 @@ export const getPouch = (opts: any = {}) => { const inMemory = require("pouchdb-adapter-memory") PouchDB.plugin(inMemory) POUCH_DB_DEFAULTS = { - prefix: undefined, // @ts-ignore adapter: "memory", } @@ -74,7 +73,6 @@ export const getPouch = (opts: any = {}) => { if (opts.onDisk) { POUCH_DB_DEFAULTS = { - prefix: undefined, // @ts-ignore adapter: "leveldb", }