From c604a076f4e8ead6de16f5119892c40def9d3e24 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Wed, 13 Jul 2022 21:50:19 +0100 Subject: [PATCH] Adding a mechanism to deprecate a view and replace it with a new one. --- packages/backend-core/src/db/constants.ts | 9 +++++- packages/backend-core/src/db/views.js | 35 +++++++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/packages/backend-core/src/db/constants.ts b/packages/backend-core/src/db/constants.ts index be0e824e61..716762dd45 100644 --- a/packages/backend-core/src/db/constants.ts +++ b/packages/backend-core/src/db/constants.ts @@ -11,7 +11,7 @@ export enum AutomationViewModes { } export enum ViewNames { - USER_BY_EMAIL = "by_email", + USER_BY_EMAIL = "by_email2", BY_API_KEY = "by_api_key", USER_BY_BUILDERS = "by_builders", LINK = "by_link", @@ -19,6 +19,13 @@ export enum ViewNames { AUTOMATION_LOGS = "automation_logs", } +export const DeprecatedViews = { + [ViewNames.USER_BY_EMAIL]: [ + // removed due to inaccuracy in view doc filter logic + "by_email", + ], +} + export enum DocumentTypes { USER = "us", WORKSPACE = "workspace", diff --git a/packages/backend-core/src/db/views.js b/packages/backend-core/src/db/views.js index e0281c6584..1e8dd7ee77 100644 --- a/packages/backend-core/src/db/views.js +++ b/packages/backend-core/src/db/views.js @@ -1,20 +1,42 @@ -const { DocumentTypes, ViewNames } = require("./utils") +const { + DocumentTypes, + ViewNames, + DeprecatedViews, + SEPARATOR, +} = require("./utils") const { getGlobalDB } = require("../tenancy") +const DESIGN_DB = "_design/database" + function DesignDoc() { return { - _id: "_design/database", + _id: DESIGN_DB, // view collation information, read before writing any complex views: // https://docs.couchdb.org/en/master/ddocs/views/collation.html#collation-specification views: {}, } } -exports.createUserEmailView = async () => { +async function removeDeprecated(db, viewName) { + if (!DeprecatedViews[viewName]) { + return + } + try { + const designDoc = await db.get(DESIGN_DB) + for (let deprecatedNames of DeprecatedViews[viewName]) { + delete designDoc.views[deprecatedNames] + } + await db.put(designDoc) + } catch (err) { + // doesn't exist, ignore + } +} + +exports.createNewUserEmailView = async () => { const db = getGlobalDB() let designDoc try { - designDoc = await db.get("_design/database") + designDoc = await db.get(DESIGN_DB) } catch (err) { // no design doc, make one designDoc = DesignDoc() @@ -22,7 +44,7 @@ exports.createUserEmailView = async () => { const view = { // if using variables in a map function need to inject them before use map: `function(doc) { - if (doc._id.startsWith("${DocumentTypes.USER}")) { + if (doc._id.startsWith("${DocumentTypes.USER}${SEPARATOR}")) { emit(doc.email.toLowerCase(), doc._id) } }`, @@ -81,7 +103,7 @@ exports.createUserBuildersView = async () => { exports.queryGlobalView = async (viewName, params, db = null) => { const CreateFuncByName = { - [ViewNames.USER_BY_EMAIL]: exports.createUserEmailView, + [ViewNames.USER_BY_EMAIL]: exports.createNewUserEmailView, [ViewNames.BY_API_KEY]: exports.createApiKeyView, [ViewNames.USER_BY_BUILDERS]: exports.createUserBuildersView, } @@ -98,6 +120,7 @@ exports.queryGlobalView = async (viewName, params, db = null) => { } catch (err) { if (err != null && err.name === "not_found") { const createFunc = CreateFuncByName[viewName] + await removeDeprecated(db, viewName) await createFunc() return exports.queryGlobalView(viewName, params) } else {