Account for duplicate row ids caused by app import

This commit is contained in:
Rory Powell 2022-01-18 12:48:54 +00:00
parent cfe7842cde
commit a09bbfb492
3 changed files with 61 additions and 40 deletions

View File

@ -129,8 +129,8 @@ const appPreDelete = async (ctx, usageContext) => {
// store the row count to delete // store the row count to delete
const rows = await getUniqueRows([ctx.appId]) const rows = await getUniqueRows([ctx.appId])
if (rows.size) { if (rows.length) {
usageContext[usageQuota.Properties.APPS] = { rowCount: rows.size } usageContext[usageQuota.Properties.APPS] = { rowCount: rows.length }
} }
} }

View File

@ -17,7 +17,7 @@ const syncRowsQuota = async db => {
// sync row count // sync row count
const usageDoc = await getUsageQuotaDoc(db) const usageDoc = await getUsageQuotaDoc(db)
usageDoc.usageQuota.rows = rows.size usageDoc.usageQuota.rows = rows.length
await db.put(usageDoc) await db.put(usageDoc)
} }

View File

@ -1,52 +1,73 @@
const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils") const { getRowParams, USER_METDATA_PREFIX } = require("../../db/utils")
const CouchDB = require("../../db") const CouchDB = require("../../db")
const { isDevAppID, getDevelopmentAppID } = require("@budibase/backend-core/db")
const ROW_EXCLUSIONS = [USER_METDATA_PREFIX] const ROW_EXCLUSIONS = [USER_METDATA_PREFIX]
/** const getAppPairs = appIds => {
* Get all rows in the given app ids. // collect the app ids into dev / prod pairs
* // keyed by the dev app id
* The returned rows may contan duplicates if there const pairs = {}
* is a production and dev app.
*/
const getAllRows = async appIds => {
const allRows = []
let appDb
for (let appId of appIds) { for (let appId of appIds) {
try { const devId = getDevelopmentAppID(appId)
appDb = new CouchDB(appId) if (!pairs[devId]) {
const response = await appDb.allDocs( pairs[devId] = {}
getRowParams(null, null, { }
include_docs: false, if (isDevAppID(appId)) {
}) pairs[devId].devId = appId
) } else {
allRows.push( pairs[devId].prodId = appId
...response.rows
.map(r => r.id)
.filter(id => {
for (let exclusion of ROW_EXCLUSIONS) {
if (id.startsWith(exclusion)) {
return false
}
}
return true
})
)
} catch (e) {
// don't error out if we can't count the app rows, just continue
} }
} }
return pairs
}
return allRows const getAppRows = async appId => {
const appDb = new CouchDB(appId)
const response = await appDb.allDocs(
getRowParams(null, null, {
include_docs: false,
})
)
return response.rows
.map(r => r.id)
.filter(id => {
for (let exclusion of ROW_EXCLUSIONS) {
if (id.startsWith(exclusion)) {
return false
}
}
return true
})
} }
/** /**
* Get all rows in the given app ids. * Return a set of all rows in the given app ids.
* * The returned rows will be unique on a per dev/prod app basis.
* The returned rows will be unique, duplicated rows across * Rows duplicates may exist across apps due to data import so they are not filtered out.
* production and dev apps will be removed.
*/ */
exports.getUniqueRows = async appIds => { exports.getUniqueRows = async appIds => {
const allRows = await getAllRows(appIds) let uniqueRows = []
return new Set(allRows) const pairs = getAppPairs(appIds)
for (let pair of Object.values(pairs)) {
let appRows = []
for (let appId of [pair.devId, pair.prodId]) {
if (!appId) {
continue
}
try {
appRows.push(await getAppRows(appId))
} catch (e) {
// don't error out if we can't count the app rows, just continue
}
}
// ensure uniqueness on a per app pair basis
// this can't be done on all rows because app import results in
// duplicate row ids across apps
uniqueRows = uniqueRows.concat(...new Set(appRows))
}
return uniqueRows
} }