Merge remote-tracking branch 'origin/v3-ui' into feature/automation-branching-ux

This commit is contained in:
Dean 2024-09-25 09:19:27 +01:00
commit 18017c0f97
2 changed files with 38 additions and 9 deletions

View File

@ -11,6 +11,7 @@ export interface DeletedApp {
}
const EXPIRY_SECONDS = 3600
const INVALID_EXPIRY_SECONDS = 60
/**
* The default populate app metadata function
@ -48,9 +49,8 @@ export async function getAppMetadata(appId: string): Promise<App | DeletedApp> {
// app DB left around, but no metadata, it is invalid
if (err && err.status === 404) {
metadata = { state: AppState.INVALID }
// don't expire the reference to an invalid app, it'll only be
// updated if a metadata doc actually gets stored (app is remade/reverted)
expiry = undefined
// expire invalid apps regularly, in-case it was only briefly invalid
expiry = INVALID_EXPIRY_SECONDS
} else {
throw err
}

View File

@ -43,6 +43,9 @@ function buildNano(couchInfo: { url: string; cookie: string }) {
}
type DBCall<T> = () => Promise<T>
type DBCallback<T> = (
db: Nano.DocumentScope<any>
) => Promise<DBCall<T>> | DBCall<T>
class CouchDBError extends Error implements DBError {
status: number
@ -171,8 +174,8 @@ export class DatabaseImpl implements Database {
}
// this function fetches the DB and handles if DB creation is needed
private async performCall<T>(
call: (db: Nano.DocumentScope<any>) => Promise<DBCall<T>> | DBCall<T>
private async performCallWithDBCreation<T>(
call: DBCallback<T>
): Promise<any> {
const db = this.getDb()
const fnc = await call(db)
@ -181,13 +184,24 @@ export class DatabaseImpl implements Database {
} catch (err: any) {
if (err.statusCode === 404 && err.reason === DATABASE_NOT_FOUND) {
await this.checkAndCreateDb()
return await this.performCall(call)
return await this.performCallWithDBCreation(call)
}
// stripping the error down the props which are safe/useful, drop everything else
throw new CouchDBError(`CouchDB error: ${err.message}`, err)
}
}
private async performCall<T>(call: DBCallback<T>): Promise<any> {
const db = this.getDb()
const fnc = await call(db)
try {
return await fnc()
} catch (err: any) {
// stripping the error down the props which are safe/useful, drop everything else
throw new CouchDBError(`CouchDB error: ${err.message}`, err)
}
}
async get<T extends Document>(id?: string): Promise<T> {
return this.performCall(db => {
if (!id) {
@ -227,6 +241,7 @@ export class DatabaseImpl implements Database {
}
async remove(idOrDoc: string | Document, rev?: string) {
// not a read call - but don't create a DB to delete a document
return this.performCall(db => {
let _id: string
let _rev: string
@ -286,7 +301,7 @@ export class DatabaseImpl implements Database {
if (!document._id) {
throw new Error("Cannot store document without _id field.")
}
return this.performCall(async db => {
return this.performCallWithDBCreation(async db => {
if (!document.createdAt) {
document.createdAt = new Date().toISOString()
}
@ -309,7 +324,7 @@ export class DatabaseImpl implements Database {
async bulkDocs(documents: AnyDocument[]) {
const now = new Date().toISOString()
return this.performCall(db => {
return this.performCallWithDBCreation(db => {
return () =>
db.bulk({
docs: documents.map(d => ({ createdAt: now, ...d, updatedAt: now })),
@ -321,7 +336,21 @@ export class DatabaseImpl implements Database {
params: DatabaseQueryOpts
): Promise<AllDocsResponse<T>> {
return this.performCall(db => {
return () => db.list(params)
return async () => {
try {
return (await db.list(params)) as AllDocsResponse<T>
} catch (err: any) {
if (err.reason === DATABASE_NOT_FOUND) {
return {
offset: 0,
total_rows: 0,
rows: [],
}
} else {
throw err
}
}
}
})
}