This removes the need for constant DB HEAD requests to check if a database exists or not. Instead, it tries to make the request, and if it fails it will check if the reason for failure is the database not existing. If it doesn't exist it runs through the same old flow to confirm that it definitely doesn't exist, and if it doesn't then it will create it.
This commit is contained in:
parent
1f958fcf53
commit
8483a53178
|
@ -19,6 +19,8 @@ import { WriteStream, ReadStream } from "fs"
|
|||
import { newid } from "../../docIds/newid"
|
||||
import { DDInstrumentedDatabase } from "../instrumentation"
|
||||
|
||||
const DATABASE_NOT_FOUND = "Database does not exist."
|
||||
|
||||
function buildNano(couchInfo: { url: string; cookie: string }) {
|
||||
return Nano({
|
||||
url: couchInfo.url,
|
||||
|
@ -31,6 +33,8 @@ function buildNano(couchInfo: { url: string; cookie: string }) {
|
|||
})
|
||||
}
|
||||
|
||||
type DBCall = () => Promise<any>
|
||||
|
||||
export function DatabaseWithConnection(
|
||||
dbName: string,
|
||||
connection: string,
|
||||
|
@ -78,7 +82,11 @@ export class DatabaseImpl implements Database {
|
|||
return this.instanceNano || DatabaseImpl.nano
|
||||
}
|
||||
|
||||
async checkSetup() {
|
||||
private getDb() {
|
||||
return this.nano().db.use(this.name)
|
||||
}
|
||||
|
||||
private async checkAndCreateDb() {
|
||||
let shouldCreate = !this.pouchOpts?.skip_setup
|
||||
// check exists in a lightweight fashion
|
||||
let exists = await this.exists()
|
||||
|
@ -95,14 +103,22 @@ export class DatabaseImpl implements Database {
|
|||
}
|
||||
}
|
||||
}
|
||||
return this.nano().db.use(this.name)
|
||||
return this.getDb()
|
||||
}
|
||||
|
||||
private async updateOutput(fnc: any) {
|
||||
// this function fetches the DB and handles if DB creation is needed
|
||||
private async performCall(
|
||||
call: (db: Nano.DocumentScope<any>) => Promise<DBCall> | DBCall
|
||||
): Promise<any> {
|
||||
const db = this.getDb()
|
||||
const fnc = await call(db)
|
||||
try {
|
||||
return await fnc()
|
||||
} catch (err: any) {
|
||||
if (err.statusCode) {
|
||||
if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
|
||||
await this.checkAndCreateDb()
|
||||
return await this.performCall(call)
|
||||
} else if (err.statusCode) {
|
||||
err.status = err.statusCode
|
||||
}
|
||||
throw err
|
||||
|
@ -110,11 +126,12 @@ export class DatabaseImpl implements Database {
|
|||
}
|
||||
|
||||
async get<T extends Document>(id?: string): Promise<T> {
|
||||
const db = await this.checkSetup()
|
||||
return this.performCall(db => {
|
||||
if (!id) {
|
||||
throw new Error("Unable to get doc without a valid _id.")
|
||||
}
|
||||
return this.updateOutput(() => db.get(id))
|
||||
return () => db.get(id)
|
||||
})
|
||||
}
|
||||
|
||||
async getMultiple<T extends Document>(
|
||||
|
@ -147,7 +164,7 @@ export class DatabaseImpl implements Database {
|
|||
}
|
||||
|
||||
async remove(idOrDoc: string | Document, rev?: string) {
|
||||
const db = await this.checkSetup()
|
||||
return this.performCall(db => {
|
||||
let _id: string
|
||||
let _rev: string
|
||||
|
||||
|
@ -162,7 +179,8 @@ export class DatabaseImpl implements Database {
|
|||
if (!_id || !_rev) {
|
||||
throw new Error("Unable to remove doc without a valid _id and _rev.")
|
||||
}
|
||||
return this.updateOutput(() => db.destroy(_id, _rev))
|
||||
return () => db.destroy(_id, _rev)
|
||||
})
|
||||
}
|
||||
|
||||
async post(document: AnyDocument, opts?: DatabasePutOpts) {
|
||||
|
@ -176,7 +194,7 @@ export class DatabaseImpl implements Database {
|
|||
if (!document._id) {
|
||||
throw new Error("Cannot store document without _id field.")
|
||||
}
|
||||
const db = await this.checkSetup()
|
||||
return this.performCall(async db => {
|
||||
if (!document.createdAt) {
|
||||
document.createdAt = new Date().toISOString()
|
||||
}
|
||||
|
@ -193,28 +211,32 @@ export class DatabaseImpl implements Database {
|
|||
}
|
||||
}
|
||||
}
|
||||
return this.updateOutput(() => db.insert(document))
|
||||
return () => db.insert(document)
|
||||
})
|
||||
}
|
||||
|
||||
async bulkDocs(documents: AnyDocument[]) {
|
||||
const db = await this.checkSetup()
|
||||
return this.updateOutput(() => db.bulk({ docs: documents }))
|
||||
return this.performCall(db => {
|
||||
return () => db.bulk({ docs: documents })
|
||||
})
|
||||
}
|
||||
|
||||
async allDocs<T extends Document>(
|
||||
params: DatabaseQueryOpts
|
||||
): Promise<AllDocsResponse<T>> {
|
||||
const db = await this.checkSetup()
|
||||
return this.updateOutput(() => db.list(params))
|
||||
return this.performCall(db => {
|
||||
return () => db.list(params)
|
||||
})
|
||||
}
|
||||
|
||||
async query<T extends Document>(
|
||||
viewName: string,
|
||||
params: DatabaseQueryOpts
|
||||
): Promise<AllDocsResponse<T>> {
|
||||
const db = await this.checkSetup()
|
||||
return this.performCall(db => {
|
||||
const [database, view] = viewName.split("/")
|
||||
return this.updateOutput(() => db.view(database, view, params))
|
||||
return () => db.view(database, view, params)
|
||||
})
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
|
@ -231,8 +253,9 @@ export class DatabaseImpl implements Database {
|
|||
}
|
||||
|
||||
async compact() {
|
||||
const db = await this.checkSetup()
|
||||
return this.updateOutput(() => db.compact())
|
||||
return this.performCall(db => {
|
||||
return () => db.compact()
|
||||
})
|
||||
}
|
||||
|
||||
// All below functions are in-frequently called, just utilise PouchDB
|
||||
|
|
|
@ -31,13 +31,6 @@ export class DDInstrumentedDatabase implements Database {
|
|||
})
|
||||
}
|
||||
|
||||
checkSetup(): Promise<DocumentScope<any>> {
|
||||
return tracer.trace("db.checkSetup", span => {
|
||||
span?.addTags({ db_name: this.name })
|
||||
return this.db.checkSetup()
|
||||
})
|
||||
}
|
||||
|
||||
get<T extends Document>(id?: string | undefined): Promise<T> {
|
||||
return tracer.trace("db.get", span => {
|
||||
span?.addTags({ db_name: this.name, doc_id: id })
|
||||
|
|
|
@ -121,7 +121,6 @@ export interface Database {
|
|||
name: string
|
||||
|
||||
exists(): Promise<boolean>
|
||||
checkSetup(): Promise<Nano.DocumentScope<any>>
|
||||
get<T extends Document>(id?: string): Promise<T>
|
||||
getMultiple<T extends Document>(
|
||||
ids: string[],
|
||||
|
|
Loading…
Reference in New Issue