Fixed mixin projections in postgres adapter (#8838)

Signed-off-by: Victor Ilyushchenko <alt13ri@gmail.com>
This commit is contained in:
Victor Ilyushchenko 2025-05-05 15:56:06 +03:00 committed by GitHub
parent 5dfef1f218
commit 4a24ca257f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 14 deletions

View File

@ -88,6 +88,7 @@ import {
DBCollectionHelper, DBCollectionHelper,
type DBDoc, type DBDoc,
doFetchTypes, doFetchTypes,
filterProjection,
getDBClient, getDBClient,
inferType, inferType,
isDataField, isDataField,
@ -662,7 +663,9 @@ abstract class PostgresAdapterBase implements DbAdapter {
const joins = this.buildJoins<T>(_class, options) const joins = this.buildJoins<T>(_class, options)
// Add workspace name as $1 // 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 showArchived = shouldShowArchived(query, options)
const secJoin = this.addSecurity(vars, query, showArchived, domain, ctx.contextData) const secJoin = this.addSecurity(vars, query, showArchived, domain, ctx.contextData)
@ -714,11 +717,11 @@ abstract class PostgresAdapterBase implements DbAdapter {
options?.associations === undefined options?.associations === undefined
) { ) {
return toFindResult( return toFindResult(
result.map((p) => parseDocWithProjection(p, domain, options?.projection)), result.map((p) => parseDocWithProjection(p, domain, projection)),
total total
) )
} else { } else {
const res = this.parseLookup<T>(result, joins, options?.projection, domain) const res = this.parseLookup<T>(result, joins, projection, domain)
return toFindResult(res, total) return toFindResult(res, total)
} }
})) as FindResult<T> })) as FindResult<T>
@ -739,6 +742,36 @@ abstract class PostgresAdapterBase implements DbAdapter {
) )
} }
private localizeProjection<T extends Doc>(
_class: Ref<Class<T>>,
projection: Projection<T> | undefined
): Projection<T> | 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<T>
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<T extends Doc>(_class: Ref<Class<T>>, options: ServerFindOptions<T> | undefined): JoinProps[] { private buildJoins<T extends Doc>(_class: Ref<Class<T>>, options: ServerFindOptions<T> | undefined): JoinProps[] {
const joins = this.buildJoin(_class, options?.lookup) const joins = this.buildJoin(_class, options?.lookup)
if (options?.domainLookup !== undefined) { if (options?.domainLookup !== undefined) {
@ -888,17 +921,8 @@ abstract class PostgresAdapterBase implements DbAdapter {
continue continue
} }
if (column === 'data') { if (column === 'data') {
const data = row[column] let data = row[column]
if (projection !== undefined) { data = filterProjection(data, projection)
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]
}
}
}
}
doc = { ...doc, ...data } doc = { ...doc, ...data }
} else { } else {
if (column === 'createdOn' || column === 'modifiedOn') { if (column === 'createdOn' || column === 'modifiedOn') {

View File

@ -554,6 +554,9 @@ export function convertArrayParams (parameters?: ParameterOrJSON<any>[]): any[]
} }
export function filterProjection<T extends Doc> (data: any, projection: Projection<T> | undefined): any { export function filterProjection<T extends Doc> (data: any, projection: Projection<T> | undefined): any {
if (projection === undefined) {
return data
}
for (const key in data) { for (const key in data) {
if (!Object.prototype.hasOwnProperty.call(projection, key) || (projection as any)[key] === 0) { if (!Object.prototype.hasOwnProperty.call(projection, key) || (projection as any)[key] === 0) {
// check nested projections in case of object // check nested projections in case of object