From 4088fd1490b670b57d0bc9674b425d295443edcc Mon Sep 17 00:00:00 2001 From: Victor Ilyushchenko Date: Mon, 5 May 2025 17:13:27 +0300 Subject: [PATCH] Cherry pick from develop 2025/05/05 (#8845) Signed-off-by: Victor Ilyushchenko --- .../src/index.ts | 15 +++--- server/postgres/src/storage.ts | 52 ++++++++++++++----- server/postgres/src/utils.ts | 3 ++ 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/server-plugins/controlled-documents-resources/src/index.ts b/server-plugins/controlled-documents-resources/src/index.ts index d22e000fc7..5ce0ee8ed2 100644 --- a/server-plugins/controlled-documents-resources/src/index.ts +++ b/server-plugins/controlled-documents-resources/src/index.ts @@ -298,14 +298,17 @@ export async function OnDocEnteredNonActionableState ( const result: Tx[] = [] for (const tx of txes) { const requests = await control.findAll(control.ctx, documents.class.DocumentRequest, { - attachedTo: tx.objectId, - status: RequestStatus.Active + attachedTo: tx.objectId }) - const cancelTxes = requests.map((request) => - control.txFactory.createTxUpdateDoc(request._class, request.space, request._id, { - status: RequestStatus.Cancelled + const cancelTxes = requests + .filter((request) => { + return request.status === RequestStatus.Active || tx.operations.state === DocumentState.Deleted }) - ) + .map((request) => + control.txFactory.createTxUpdateDoc(request._class, request.space, request._id, { + status: RequestStatus.Cancelled + }) + ) await control.apply(control.ctx, [ ...cancelTxes, control.txFactory.createTxUpdateDoc(tx.objectClass, tx.objectSpace, tx.objectId, { diff --git a/server/postgres/src/storage.ts b/server/postgres/src/storage.ts index c4ed31a03f..93e43782e8 100644 --- a/server/postgres/src/storage.ts +++ b/server/postgres/src/storage.ts @@ -85,6 +85,7 @@ import { DBCollectionHelper, type DBDoc, doFetchTypes, + filterProjection, getDBClient, inferType, isDataField, @@ -664,7 +665,9 @@ abstract class PostgresAdapterBase implements DbAdapter { const joins = this.buildJoins(_class, options) // Add workspace name as $1 - const select = `SELECT ${this.getProjection(vars, domain, options?.projection, joins, options?.associations)} FROM ${domain}` + const projection = this.localizeProjection(_class, options?.projection ?? undefined) + + const select = `SELECT ${this.getProjection(vars, domain, projection, joins, options?.associations)} FROM ${domain}` const showArchived = shouldShowArchived(query, options) const secJoin = this.addSecurity(vars, query, showArchived, domain, ctx.contextData) @@ -716,11 +719,11 @@ abstract class PostgresAdapterBase implements DbAdapter { options?.associations === undefined ) { return toFindResult( - result.map((p) => parseDocWithProjection(p, domain, options?.projection)), + result.map((p) => parseDocWithProjection(p, domain, projection)), total ) } else { - const res = this.parseLookup(result, joins, options?.projection, domain) + const res = this.parseLookup(result, joins, projection, domain) return toFindResult(res, total) } })) as FindResult @@ -741,6 +744,36 @@ abstract class PostgresAdapterBase implements DbAdapter { ) } + private localizeProjection( + _class: Ref>, + projection: Projection | undefined + ): Projection | undefined { + if (projection === undefined) return + + if (!this.hierarchy.isMixin(_class)) { + return projection + } + + projection = { ...projection } + for (const key in projection) { + if (key.includes('.')) continue + try { + const attr = this.hierarchy.findAttribute(_class, key) + if (attr !== undefined && this.hierarchy.isMixin(attr.attributeOf)) { + const newKey = `${attr.attributeOf}.${attr.name}` as keyof Projection + projection[newKey] = projection[key] + + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete projection[key] + } + } catch (err: any) { + // ignore, if + } + } + + return projection + } + private buildJoins(_class: Ref>, options: ServerFindOptions | undefined): JoinProps[] { const joins = this.buildJoin(_class, options?.lookup) if (options?.domainLookup !== undefined) { @@ -890,17 +923,8 @@ abstract class PostgresAdapterBase implements DbAdapter { continue } if (column === 'data') { - const data = row[column] - if (projection !== undefined) { - if (projection !== undefined) { - for (const key in data) { - if (!Object.prototype.hasOwnProperty.call(projection, key) || (projection as any)[key] === 0) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete data[key] - } - } - } - } + let data = row[column] + data = filterProjection(data, projection) doc = { ...doc, ...data } } else { if (column === 'createdOn' || column === 'modifiedOn') { diff --git a/server/postgres/src/utils.ts b/server/postgres/src/utils.ts index 226876b084..de7330879e 100644 --- a/server/postgres/src/utils.ts +++ b/server/postgres/src/utils.ts @@ -557,6 +557,9 @@ export function convertArrayParams (parameters?: ParameterOrJSON[]): any[] } export function filterProjection (data: any, projection: Projection | undefined): any { + if (projection === undefined) { + return data + } for (const key in data) { if (!Object.prototype.hasOwnProperty.call(projection, key) || (projection as any)[key] === 0) { // check nested projections in case of object