2022-10-12 18:02:23 +02:00
|
|
|
import pouch from "./pouch"
|
|
|
|
import env from "../environment"
|
|
|
|
import { checkSlashesInUrl } from "../helpers"
|
|
|
|
import fetch from "node-fetch"
|
|
|
|
import { PouchOptions, CouchFindOptions } from "@budibase/types"
|
2021-04-20 18:17:44 +02:00
|
|
|
|
2022-10-12 18:02:23 +02:00
|
|
|
const openDbs: string[] = []
|
|
|
|
let PouchDB: any
|
2022-03-29 17:03:44 +02:00
|
|
|
let initialised = false
|
2022-05-20 19:29:37 +02:00
|
|
|
const dbList = new Set()
|
2022-03-29 17:03:44 +02:00
|
|
|
|
2022-07-14 20:02:00 +02:00
|
|
|
if (env.MEMORY_LEAK_CHECK) {
|
2022-07-14 17:02:05 +02:00
|
|
|
setInterval(() => {
|
|
|
|
console.log("--- OPEN DBS ---")
|
|
|
|
console.log(openDbs)
|
|
|
|
}, 5000)
|
|
|
|
}
|
|
|
|
|
2022-03-29 17:03:44 +02:00
|
|
|
const put =
|
2022-10-12 18:02:23 +02:00
|
|
|
(dbPut: any) =>
|
|
|
|
async (doc: any, options = {}) => {
|
2022-03-30 15:24:04 +02:00
|
|
|
if (!doc.createdAt) {
|
|
|
|
doc.createdAt = new Date().toISOString()
|
|
|
|
}
|
|
|
|
doc.updatedAt = new Date().toISOString()
|
|
|
|
return dbPut(doc, options)
|
2022-03-29 17:03:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const checkInitialised = () => {
|
|
|
|
if (!initialised) {
|
|
|
|
throw new Error("init has not been called")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-12 18:02:23 +02:00
|
|
|
export async function init(opts: PouchOptions) {
|
2022-03-29 17:03:44 +02:00
|
|
|
PouchDB = pouch.getPouch(opts)
|
|
|
|
initialised = true
|
2021-04-15 17:45:21 +02:00
|
|
|
}
|
2021-04-15 17:57:01 +02:00
|
|
|
|
2022-04-19 20:42:52 +02:00
|
|
|
// 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
|
2022-10-12 18:02:23 +02:00
|
|
|
export async function dangerousGetDB(dbName: string, opts: any) {
|
2022-03-29 17:03:44 +02:00
|
|
|
checkInitialised()
|
2022-05-20 19:29:37 +02:00
|
|
|
if (env.isTest()) {
|
|
|
|
dbList.add(dbName)
|
|
|
|
}
|
2022-03-29 17:03:44 +02:00
|
|
|
const db = new PouchDB(dbName, opts)
|
2022-07-14 20:02:00 +02:00
|
|
|
if (env.MEMORY_LEAK_CHECK) {
|
2022-07-14 17:02:05 +02:00
|
|
|
openDbs.push(db.name)
|
|
|
|
}
|
2022-03-29 17:03:44 +02:00
|
|
|
const dbPut = db.put
|
|
|
|
db.put = put(dbPut)
|
|
|
|
return db
|
2021-04-20 18:17:44 +02:00
|
|
|
}
|
2021-05-14 17:31:07 +02:00
|
|
|
|
2022-04-20 18:33:42 +02:00
|
|
|
// use this function if you have called dangerousGetDB - close
|
|
|
|
// the databases you've opened once finished
|
2022-10-12 18:02:23 +02:00
|
|
|
export async function closeDB(db: PouchDB.Database) {
|
2022-04-21 15:56:14 +02:00
|
|
|
if (!db || env.isTest()) {
|
2022-04-20 18:33:42 +02:00
|
|
|
return
|
|
|
|
}
|
2022-07-14 20:02:00 +02:00
|
|
|
if (env.MEMORY_LEAK_CHECK) {
|
2022-07-14 17:02:05 +02:00
|
|
|
openDbs.splice(openDbs.indexOf(db.name), 1)
|
|
|
|
}
|
2022-04-20 18:33:42 +02:00
|
|
|
try {
|
2022-04-27 16:58:55 +02:00
|
|
|
// specifically await so that if there is an error, it can be ignored
|
|
|
|
return await db.close()
|
2022-04-20 18:33:42 +02:00
|
|
|
} catch (err) {
|
|
|
|
// ignore error, already closed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-19 20:42:52 +02:00
|
|
|
// we have to use a callback for this so that we can close
|
|
|
|
// the DB when we're done, without this manual requests would
|
|
|
|
// need to close the database when done with it to avoid memory leaks
|
2022-10-12 18:02:23 +02:00
|
|
|
export async function doWithDB(dbName: string, cb: any, opts = {}) {
|
2022-04-19 20:42:52 +02:00
|
|
|
const db = exports.dangerousGetDB(dbName, opts)
|
|
|
|
// need this to be async so that we can correctly close DB after all
|
|
|
|
// async operations have been completed
|
2022-04-21 00:10:39 +02:00
|
|
|
try {
|
|
|
|
return await cb(db)
|
|
|
|
} finally {
|
|
|
|
await exports.closeDB(db)
|
|
|
|
}
|
2022-04-19 20:42:52 +02:00
|
|
|
}
|
|
|
|
|
2022-10-12 18:02:23 +02:00
|
|
|
export function allDbs() {
|
2022-05-20 19:29:37 +02:00
|
|
|
if (!env.isTest()) {
|
|
|
|
throw new Error("Cannot be used outside test environment.")
|
|
|
|
}
|
2022-03-29 17:03:44 +02:00
|
|
|
checkInitialised()
|
2022-05-20 19:29:37 +02:00
|
|
|
return [...dbList]
|
2021-05-14 17:31:07 +02:00
|
|
|
}
|
2022-10-12 18:02:23 +02:00
|
|
|
|
|
|
|
export async function directCouchQuery(
|
|
|
|
path: string,
|
|
|
|
method: string = "GET",
|
|
|
|
body?: any
|
|
|
|
) {
|
|
|
|
let { url, cookie } = pouch.getCouchInfo()
|
|
|
|
const couchUrl = `${url}/${path}`
|
|
|
|
const params: any = {
|
|
|
|
method: method,
|
|
|
|
headers: {
|
|
|
|
Authorization: cookie,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if (body && method !== "GET") {
|
|
|
|
params.body = body
|
|
|
|
}
|
|
|
|
const response = await fetch(checkSlashesInUrl(encodeURI(couchUrl)), params)
|
|
|
|
if (response.status < 300) {
|
|
|
|
return await response.json()
|
|
|
|
} else {
|
|
|
|
throw "Cannot connect to CouchDB instance"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function directCouchFind(dbName: string, opts: CouchFindOptions) {
|
|
|
|
const json = await directCouchQuery(`${dbName}/_find`, "POST", opts)
|
|
|
|
return { rows: json.docs, bookmark: json.bookmark }
|
|
|
|
}
|