From 7441fa146d5568b6fd8e6aa6b45ca63b6c82f4b7 Mon Sep 17 00:00:00 2001
From: Alexey Zinoviev <alexey.zinoviev@xored.com>
Date: Thu, 3 Oct 2024 13:33:41 +0400
Subject: [PATCH] Qfix: empty where clause (#6793)

Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
---
 dev/tool/src/db.ts                         | 31 ++++++++++++++++------
 server/account/src/collections/postgres.ts | 16 ++++++++---
 2 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/dev/tool/src/db.ts b/dev/tool/src/db.ts
index 7bd1d69e33..d55013cb73 100644
--- a/dev/tool/src/db.ts
+++ b/dev/tool/src/db.ts
@@ -140,6 +140,7 @@ export async function moveAccountDbFromMongoToPG (
   mongoDb: AccountDB,
   pgDb: AccountDB
 ): Promise<void> {
+  // [accountId, workspaceId]
   const workspaceAssignments: [ObjectId, ObjectId][] = []
   const accounts = await listAccounts(mongoDb)
   const workspaces = await listWorkspacesPure(mongoDb)
@@ -153,14 +154,18 @@ export async function moveAccountDbFromMongoToPG (
 
     delete (pgAccount as any).workspaces
 
+    if (pgAccount.createdOn === undefined) {
+      pgAccount.createdOn = Date.now()
+    }
+
+    for (const workspace of mongoAccount.workspaces) {
+      workspaceAssignments.push([pgAccount._id, workspace.toString()])
+    }
+
     const exists = await getAccount(pgDb, pgAccount.email)
     if (exists === null) {
       await pgDb.account.insertOne(pgAccount)
       ctx.info('Moved account', { email: pgAccount.email })
-
-      for (const workspace of mongoAccount.workspaces) {
-        workspaceAssignments.push([pgAccount._id, workspace.toString()])
-      }
     }
   }
 
@@ -202,9 +207,19 @@ export async function moveAccountDbFromMongoToPG (
     }
   }
 
-  if (workspaceAssignments.length > 0) {
-    for (const [accountId, workspaceId] of workspaceAssignments) {
-      await pgDb.assignWorkspace(accountId, workspaceId)
-    }
+  const pgAssignments = (await listAccounts(pgDb)).reduce<Record<ObjectId, ObjectId[]>>((assignments, acc) => {
+    assignments[acc._id] = acc.workspaces
+
+    return assignments
+  }, {})
+  const assignmentsToInsert = workspaceAssignments.filter(
+    ([accountId, workspaceId]) =>
+      pgAssignments[accountId] === undefined || !pgAssignments[accountId].includes(workspaceId)
+  )
+
+  for (const [accountId, workspaceId] of assignmentsToInsert) {
+    await pgDb.assignWorkspace(accountId, workspaceId)
   }
+
+  ctx.info('Assignments made', { count: assignmentsToInsert.length })
 }
diff --git a/server/account/src/collections/postgres.ts b/server/account/src/collections/postgres.ts
index 551731e5d8..04bbb88aa4 100644
--- a/server/account/src/collections/postgres.ts
+++ b/server/account/src/collections/postgres.ts
@@ -59,6 +59,10 @@ export abstract class PostgresDbCollection<T extends Record<string, any>> implem
   }
 
   protected buildWhereClause (query: Query<T>, lastRefIdx: number = 0): [string, any[]] {
+    if (Object.keys(query).length === 0) {
+      return ['', []]
+    }
+
     const whereChunks: string[] = []
     const values: any[] = []
     let currIdx: number = lastRefIdx
@@ -131,7 +135,9 @@ export abstract class PostgresDbCollection<T extends Record<string, any>> implem
     const sqlChunks: string[] = [this.buildSelectClause()]
     const [whereClause, whereValues] = this.buildWhereClause(query)
 
-    sqlChunks.push(whereClause)
+    if (whereClause !== '') {
+      sqlChunks.push(whereClause)
+    }
 
     if (sort !== undefined) {
       sqlChunks.push(this.buildSortClause(sort))
@@ -200,7 +206,9 @@ export abstract class PostgresDbCollection<T extends Record<string, any>> implem
     const [whereClause, whereValues] = this.buildWhereClause(query, updateValues.length)
 
     sqlChunks.push(updateClause)
-    sqlChunks.push(whereClause)
+    if (whereClause !== '') {
+      sqlChunks.push(whereClause)
+    }
 
     const finalSql = sqlChunks.join(' ')
     await this.client.query(finalSql, [...updateValues, ...whereValues])
@@ -210,7 +218,9 @@ export abstract class PostgresDbCollection<T extends Record<string, any>> implem
     const sqlChunks: string[] = [`DELETE FROM ${this.name}`]
     const [whereClause, whereValues] = this.buildWhereClause(query)
 
-    sqlChunks.push(whereClause)
+    if (whereClause !== '') {
+      sqlChunks.push(whereClause)
+    }
 
     const finalSql = sqlChunks.join(' ')
     await this.client.query(finalSql, whereValues)