@backstage/plugin-catalog-backend 3.6.0 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend
|
|
2
2
|
|
|
3
|
+
## 3.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 250778e: Fixed a performance regression in the `/entity-facets` endpoint when filters or permission conditions are applied, by routing the EXISTS-based filter through `final_entities` instead of correlating against the much larger `search` table.
|
|
8
|
+
|
|
3
9
|
## 3.6.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
|
@@ -441,13 +441,15 @@ class DefaultEntitiesCatalog {
|
|
|
441
441
|
count: this.database.raw("count(DISTINCT search.entity_id)")
|
|
442
442
|
}).groupBy(["search.key", "search.original_value"]);
|
|
443
443
|
if (request.filter || request.query) {
|
|
444
|
+
const entityIdSubquery = this.database("final_entities").select("final_entities.entity_id").whereNotNull("final_entities.final_entity");
|
|
444
445
|
applyEntityFilterToQuery.applyEntityFilterToQuery({
|
|
445
446
|
filter: request.filter,
|
|
446
447
|
query: request.query,
|
|
447
|
-
targetQuery:
|
|
448
|
-
onEntityIdField: "
|
|
448
|
+
targetQuery: entityIdSubquery,
|
|
449
|
+
onEntityIdField: "final_entities.entity_id",
|
|
449
450
|
knex: this.database
|
|
450
451
|
});
|
|
452
|
+
query.whereIn("search.entity_id", entityIdSubquery);
|
|
451
453
|
}
|
|
452
454
|
const rows = await query;
|
|
453
455
|
const facets = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefaultEntitiesCatalog.cjs.js","sources":["../../src/service/DefaultEntitiesCatalog.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { chunk as lodashChunk, isEqual } from 'lodash';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n EntityOrder,\n EntityPagination,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport {\n DbFinalEntitiesRow,\n DbPageInfo,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n DbSearchRow,\n} from '../database/tables';\nimport { Stitcher } from '../stitching/types';\n\nimport {\n expandLegacyCompoundRelationsInEntity,\n isQueryEntitiesCursorRequest,\n isQueryEntitiesInitialRequest,\n} from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { applyEntityFilterToQuery } from './request/applyEntityFilterToQuery';\nimport { processRawEntitiesResult } from './response';\n\nconst DEFAULT_LIMIT = 200;\n\nfunction parsePagination(input?: EntityPagination): EntityPagination {\n if (!input) {\n return {};\n }\n\n let { limit, offset } = input;\n\n if (input.after === undefined) {\n return { limit, offset };\n }\n\n let cursor;\n try {\n const json = Buffer.from(input.after, 'base64').toString('utf8');\n cursor = JSON.parse(json);\n } catch {\n throw new InputError('Malformed after cursor, could not be parsed');\n }\n\n if (cursor.limit !== undefined) {\n if (!Number.isInteger(cursor.limit)) {\n throw new InputError('Malformed after cursor, limit was not an number');\n }\n limit = cursor.limit;\n }\n\n if (cursor.offset !== undefined) {\n if (!Number.isInteger(cursor.offset)) {\n throw new InputError('Malformed after cursor, offset was not a number');\n }\n offset = cursor.offset;\n }\n\n return { limit, offset };\n}\n\nfunction stringifyPagination(\n input: Required<Omit<EntityPagination, 'after'>>,\n): string {\n const { limit, offset } = input;\n const json = JSON.stringify({ limit, offset });\n const base64 = Buffer.from(json, 'utf8').toString('base64');\n return base64;\n}\n\nexport class DefaultEntitiesCatalog implements EntitiesCatalog {\n private readonly database: Knex;\n private readonly logger: LoggerService;\n private readonly stitcher: Stitcher;\n private readonly enableRelationsCompatibility: boolean;\n\n constructor(options: {\n database: Knex;\n logger: LoggerService;\n stitcher: Stitcher;\n enableRelationsCompatibility?: boolean;\n }) {\n this.database = options.database;\n this.logger = options.logger;\n this.stitcher = options.stitcher;\n this.enableRelationsCompatibility = Boolean(\n options.enableRelationsCompatibility,\n );\n }\n\n async entities(request?: EntitiesRequest): Promise<EntitiesResponse> {\n const db = this.database;\n const { limit, offset } = parsePagination(request?.pagination);\n\n let entitiesQuery =\n db<DbFinalEntitiesRow>('final_entities').select('final_entities.*');\n\n request?.order?.forEach(({ field }, index) => {\n const alias = `order_${index}`;\n entitiesQuery = entitiesQuery.leftOuterJoin(\n { [alias]: 'search' },\n function search(inner) {\n inner\n .on(`${alias}.entity_id`, 'final_entities.entity_id')\n .andOn(`${alias}.key`, db.raw('?', [field]));\n },\n );\n });\n\n entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity');\n\n if (request?.filter) {\n entitiesQuery = applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: entitiesQuery,\n onEntityIdField: 'final_entities.entity_id',\n knex: db,\n });\n }\n\n request?.order?.forEach(({ order }, index) => {\n if (db.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order, nulls: 'last' },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order: undefined, nulls: 'last' },\n { column: `order_${index}.value`, order },\n ]);\n }\n });\n\n if (!request?.order) {\n entitiesQuery = entitiesQuery.orderBy('final_entities.entity_ref', 'asc'); // default sort\n } else {\n entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort\n }\n\n if (limit !== undefined) {\n entitiesQuery = entitiesQuery.limit(limit + 1);\n }\n if (offset !== undefined) {\n entitiesQuery = entitiesQuery.offset(offset);\n }\n\n let rows = await entitiesQuery;\n let pageInfo: DbPageInfo;\n if (limit === undefined || rows.length <= limit) {\n pageInfo = { hasNextPage: false };\n } else {\n rows = rows.slice(0, -1);\n pageInfo = {\n hasNextPage: true,\n endCursor: stringifyPagination({\n limit,\n offset: (offset ?? 0) + limit,\n }),\n };\n }\n\n return {\n entities: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n this.enableRelationsCompatibility\n ? e => {\n expandLegacyCompoundRelationsInEntity(e);\n if (request?.fields) {\n return request.fields(e);\n }\n return e;\n }\n : request?.fields,\n ),\n pageInfo,\n };\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise<EntitiesBatchResponse> {\n const lookup = new Map<string, string>();\n\n for (const chunk of lodashChunk(request.entityRefs, 200)) {\n let query = this.database<DbFinalEntitiesRow>('final_entities')\n .select({\n entityRef: 'final_entities.entity_ref',\n entity: 'final_entities.final_entity',\n })\n .whereIn('final_entities.entity_ref', chunk);\n\n if (request?.filter || request?.query) {\n query = applyEntityFilterToQuery({\n filter: request.filter,\n query: request.query,\n targetQuery: query,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n for (const row of await query) {\n lookup.set(row.entityRef, row.entity ? row.entity : null);\n }\n }\n\n const items = request.entityRefs.map(ref => lookup.get(ref) ?? null);\n\n return { items: processRawEntitiesResult(items, request.fields) };\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise<QueryEntitiesResponse> {\n const limit = request.limit ?? DEFAULT_LIMIT;\n\n const cursor: Omit<Cursor, 'orderFieldValues'> & {\n orderFieldValues?: (string | null)[];\n skipTotalItems: boolean;\n } = {\n orderFields: [],\n isPrevious: false,\n ...parseCursorFromRequest(request),\n };\n\n // For performance reasons we invoke the count query only on the first\n // request. The result is then embedded into the cursor for subsequent\n // requests. Threfore this can be undefined here, but will then get\n // populated further down.\n const shouldComputeTotalItems =\n cursor.totalItems === undefined && !cursor.skipTotalItems;\n const isFetchingBackwards = cursor.isPrevious;\n\n if (cursor.orderFields.length > 1) {\n this.logger.warn(`Only one sort field is supported, ignoring the rest`);\n }\n\n const sortField = cursor.orderFields.at(0);\n\n // The first part of the query builder is a subquery that applies all of the\n // filtering.\n const dbQuery = this.database.with(\n 'filtered',\n ['entity_id', 'final_entity', ...(sortField ? ['value'] : [])],\n inner => {\n inner\n .from<DbFinalEntitiesRow>('final_entities')\n .whereNotNull('final_entity');\n\n if (sortField) {\n inner\n .distinct()\n .leftOuterJoin('search', qb =>\n qb\n .on('search.entity_id', 'final_entities.entity_id')\n .andOnVal('search.key', sortField.field),\n )\n .select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n value: 'search.value',\n });\n } else {\n inner.select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n });\n }\n\n // Add regular filters and/or predicate query, if given\n if (cursor.filter || cursor.query) {\n applyEntityFilterToQuery({\n filter: cursor.filter,\n query: cursor.query,\n targetQuery: inner,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n // Add full text search filters, if given\n const normalizedFullTextFilterTerm =\n cursor.fullTextFilter?.term?.trim();\n const textFilterFields = cursor.fullTextFilter?.fields ?? [\n sortField?.field || 'metadata.uid',\n ];\n if (normalizedFullTextFilterTerm) {\n if (\n textFilterFields.length === 1 &&\n textFilterFields[0] === sortField?.field\n ) {\n // If there is one item, apply the like query to the top level query which is already\n // filtered based on the singular sortField.\n inner.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n } else {\n const matchQuery = this.database<DbSearchRow>('search')\n .select('search.entity_id')\n // textFilterFields must be lowercased to match searchable keys in database, i.e. spec.profile.displayName -> spec.profile.displayname\n .whereIn(\n 'search.key',\n textFilterFields.map(field => field.toLocaleLowerCase('en-US')),\n )\n .andWhere(function keyFilter() {\n this.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase(\n 'en-US',\n )}%`,\n );\n });\n inner.andWhere('final_entities.entity_id', 'in', matchQuery);\n }\n }\n },\n );\n\n // Only pay the cost of counting the number of items if needed\n if (shouldComputeTotalItems) {\n // Note the intentional cross join here. The filtered_count dataset is\n // always exactly one row, so it won't grow the result unnecessarily. But\n // it's also important that there IS at least one row, because even if the\n // filtered dataset is empty, we still want to know the total number of\n // items.\n dbQuery\n .with('filtered_count', ['count'], inner =>\n inner.from('filtered').count('*', { as: 'count' }),\n )\n .fromRaw('filtered_count, filtered')\n .select('count', 'filtered.*');\n } else {\n dbQuery.from('filtered').select('*');\n }\n\n const isOrderingDescending = sortField?.order === 'desc';\n\n // Move forward (or backward) in the set to the correct cursor position\n if (cursor.orderFieldValues) {\n if (cursor.orderFieldValues.length === 2) {\n // The first will be the sortField value, the second the entity_id\n const [first, second] = cursor.orderFieldValues;\n dbQuery.andWhere(function nested() {\n this.where(\n 'filtered.value',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n first,\n )\n .orWhere('filtered.value', '=', first)\n .andWhere(\n 'filtered.entity_id',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n second,\n );\n });\n } else if (cursor.orderFieldValues.length === 1) {\n // This will be the entity_id\n const [first] = cursor.orderFieldValues;\n dbQuery.andWhere('entity_id', isFetchingBackwards ? '<' : '>', first);\n }\n }\n\n // Add the ordering\n let order = sortField?.order ?? 'asc';\n if (isFetchingBackwards) {\n order = invertOrder(order);\n }\n if (this.database.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order,\n nulls: 'last',\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order: undefined,\n nulls: 'last',\n },\n {\n column: 'filtered.value',\n order,\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n }\n\n // Apply a manually set initial offset\n if (\n isQueryEntitiesInitialRequest(request) &&\n request.offset !== undefined\n ) {\n dbQuery.offset(request.offset);\n }\n // fetch an extra item to check if there are more items.\n dbQuery.limit(isFetchingBackwards ? limit : limit + 1);\n\n const rows = shouldComputeTotalItems || limit > 0 ? await dbQuery : [];\n\n let totalItems: number;\n if (cursor.totalItems !== undefined) {\n totalItems = cursor.totalItems;\n } else if (cursor.skipTotalItems) {\n totalItems = 0;\n } else if (rows.length) {\n totalItems = Number(rows[0].count);\n } else {\n totalItems = 0;\n }\n\n if (isFetchingBackwards) {\n rows.reverse();\n }\n const hasMoreResults =\n limit > 0 && (isFetchingBackwards || rows.length > limit);\n\n // discard the extra item only when fetching forward.\n if (rows.length > limit) {\n rows.length -= 1;\n }\n\n const isInitialRequest = cursor.firstSortFieldValues === undefined;\n\n const firstRow = rows[0];\n const lastRow = rows[rows.length - 1];\n\n const firstSortFieldValues =\n cursor.firstSortFieldValues || sortFieldsFromRow(firstRow, sortField);\n\n const nextCursor: Cursor | undefined = hasMoreResults\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(lastRow, sortField),\n firstSortFieldValues,\n isPrevious: false,\n totalItems,\n }\n : undefined;\n\n const prevCursor: Cursor | undefined =\n !isInitialRequest &&\n rows.length > 0 &&\n !isEqual(\n sortFieldsFromRow(firstRow, sortField),\n cursor.firstSortFieldValues,\n )\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(firstRow, sortField),\n firstSortFieldValues: cursor.firstSortFieldValues,\n isPrevious: true,\n totalItems,\n }\n : undefined;\n\n return {\n items: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n request.fields,\n ),\n pageInfo: {\n ...(!!prevCursor && { prevCursor }),\n ...(!!nextCursor && { nextCursor }),\n },\n totalItems,\n };\n }\n\n async removeEntityByUid(uid: string): Promise<void> {\n const relationPeerRefs = await this.database.transaction(async tx => {\n const dbConfig = tx.client.config;\n\n // Clear the hashed state of the immediate parents of the deleted entity.\n // This makes sure that when they get reprocessed, their output is written\n // down again. The reason for wanting to do this, is that if the user\n // deletes entities that ARE still emitted by the parent, the parent\n // processing will still generate the same output hash as always, which\n // means it'll never try to write down the children again (it assumes that\n // they already exist). This means that without the code below, the database\n // never \"heals\" from accidental deletes.\n if (dbConfig.client.includes('mysql')) {\n // MySQL doesn't support the syntax we need to do this in a single query,\n // http://dev.mysql.com/doc/refman/5.6/en/update.html\n const results = await tx<DbRefreshStateRow>('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n await tx<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: tx.fn.now(),\n })\n .whereIn(\n 'entity_id',\n results.map(key => key.entity_id),\n );\n } else {\n await tx<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: tx.fn.now(),\n })\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n }\n\n const relationPeers = await tx\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.target_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.target_entity_ref' })\n .union(other =>\n other\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.source_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.source_entity_ref' }),\n );\n\n await tx<DbRefreshStateRow>('refresh_state')\n .where('entity_id', uid)\n .delete();\n\n return new Set(relationPeers.map(p => p.ref));\n });\n\n if (relationPeerRefs.size > 0) {\n await this.stitcher.stitch({\n entityRefs: relationPeerRefs,\n });\n }\n }\n\n async entityAncestry(rootRef: string): Promise<EntityAncestryResponse> {\n const [rootRow] = await this.database<DbFinalEntitiesRow>('final_entities')\n .where('final_entities.entity_ref', '=', rootRef)\n .select({\n entityJson: 'final_entities.final_entity',\n });\n\n if (!rootRow) {\n throw new NotFoundError(`No such entity ${rootRef}`);\n }\n\n const rootEntity = JSON.parse(rootRow.entityJson) as Entity;\n const seenEntityRefs = new Set<string>();\n const todo = new Array<Entity>();\n const items = new Array<{ entity: Entity; parentEntityRefs: string[] }>();\n\n for (\n let current: Entity | undefined = rootEntity;\n current;\n current = todo.pop()\n ) {\n const currentRef = stringifyEntityRef(current);\n seenEntityRefs.add(currentRef);\n\n const parentRows = await this.database<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n )\n .innerJoin<DbFinalEntitiesRow>('final_entities', {\n 'refresh_state_references.source_entity_ref':\n 'final_entities.entity_ref',\n })\n .where('refresh_state_references.target_entity_ref', '=', currentRef)\n .select({\n parentEntityRef: 'final_entities.entity_ref',\n parentEntityJson: 'final_entities.final_entity',\n });\n\n const parentRefs: string[] = [];\n for (const { parentEntityRef, parentEntityJson } of parentRows) {\n parentRefs.push(parentEntityRef);\n if (!seenEntityRefs.has(parentEntityRef)) {\n seenEntityRefs.add(parentEntityRef);\n todo.push(JSON.parse(parentEntityJson));\n }\n }\n\n items.push({\n entity: current,\n parentEntityRefs: parentRefs,\n });\n }\n\n return {\n rootEntityRef: stringifyEntityRef(rootEntity),\n items,\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {\n const query = this.database<DbSearchRow>('search')\n .whereIn(\n 'search.key',\n request.facets.map(f => f.toLocaleLowerCase('en-US')),\n )\n .whereNotNull('search.original_value')\n .select({\n facet: 'search.key',\n value: 'search.original_value',\n count: this.database.raw('count(DISTINCT search.entity_id)'),\n })\n .groupBy(['search.key', 'search.original_value']);\n\n if (request.filter || request.query) {\n applyEntityFilterToQuery({\n filter: request.filter,\n query: request.query,\n targetQuery: query,\n onEntityIdField: 'search.entity_id',\n knex: this.database,\n });\n }\n\n const rows = await query;\n\n const facets: EntityFacetsResponse['facets'] = {};\n for (const facet of request.facets) {\n const facetLowercase = facet.toLocaleLowerCase('en-US');\n facets[facet] = rows\n .filter(row => row.facet === facetLowercase)\n .map(row => ({\n value: String(row.value),\n count: Number(row.count),\n }));\n }\n\n return { facets };\n }\n}\n\nfunction parseCursorFromRequest(\n request?: QueryEntitiesRequest,\n): Partial<Cursor> & { skipTotalItems: boolean } {\n if (isQueryEntitiesInitialRequest(request)) {\n const {\n filter,\n query,\n orderFields: sortFields = [],\n fullTextFilter,\n skipTotalItems = false,\n } = request;\n return {\n filter,\n query,\n orderFields: sortFields,\n fullTextFilter,\n skipTotalItems,\n };\n }\n if (isQueryEntitiesCursorRequest(request)) {\n return {\n ...request.cursor,\n // Doesn't matter here\n skipTotalItems: false,\n };\n }\n return {\n skipTotalItems: false,\n };\n}\n\nfunction invertOrder(order: EntityOrder['order']) {\n return order === 'asc' ? 'desc' : 'asc';\n}\n\nfunction sortFieldsFromRow(\n row: DbSearchRow & DbFinalEntitiesRow,\n sortField?: EntityOrder | undefined,\n) {\n return sortField ? [row?.value, row?.entity_id] : [row?.entity_id];\n}\n"],"names":["InputError","applyEntityFilterToQuery","processRawEntitiesResult","expandLegacyCompoundRelationsInEntity","lodashChunk","isQueryEntitiesInitialRequest","isEqual","NotFoundError","stringifyEntityRef","isQueryEntitiesCursorRequest"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DefaultEntitiesCatalog.cjs.js","sources":["../../src/service/DefaultEntitiesCatalog.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity, stringifyEntityRef } from '@backstage/catalog-model';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { chunk as lodashChunk, isEqual } from 'lodash';\nimport {\n Cursor,\n EntitiesBatchRequest,\n EntitiesBatchResponse,\n EntitiesCatalog,\n EntitiesRequest,\n EntitiesResponse,\n EntityAncestryResponse,\n EntityFacetsRequest,\n EntityFacetsResponse,\n EntityOrder,\n EntityPagination,\n QueryEntitiesRequest,\n QueryEntitiesResponse,\n} from '../catalog/types';\nimport {\n DbFinalEntitiesRow,\n DbPageInfo,\n DbRefreshStateReferencesRow,\n DbRefreshStateRow,\n DbRelationsRow,\n DbSearchRow,\n} from '../database/tables';\nimport { Stitcher } from '../stitching/types';\n\nimport {\n expandLegacyCompoundRelationsInEntity,\n isQueryEntitiesCursorRequest,\n isQueryEntitiesInitialRequest,\n} from './util';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { applyEntityFilterToQuery } from './request/applyEntityFilterToQuery';\nimport { processRawEntitiesResult } from './response';\n\nconst DEFAULT_LIMIT = 200;\n\nfunction parsePagination(input?: EntityPagination): EntityPagination {\n if (!input) {\n return {};\n }\n\n let { limit, offset } = input;\n\n if (input.after === undefined) {\n return { limit, offset };\n }\n\n let cursor;\n try {\n const json = Buffer.from(input.after, 'base64').toString('utf8');\n cursor = JSON.parse(json);\n } catch {\n throw new InputError('Malformed after cursor, could not be parsed');\n }\n\n if (cursor.limit !== undefined) {\n if (!Number.isInteger(cursor.limit)) {\n throw new InputError('Malformed after cursor, limit was not an number');\n }\n limit = cursor.limit;\n }\n\n if (cursor.offset !== undefined) {\n if (!Number.isInteger(cursor.offset)) {\n throw new InputError('Malformed after cursor, offset was not a number');\n }\n offset = cursor.offset;\n }\n\n return { limit, offset };\n}\n\nfunction stringifyPagination(\n input: Required<Omit<EntityPagination, 'after'>>,\n): string {\n const { limit, offset } = input;\n const json = JSON.stringify({ limit, offset });\n const base64 = Buffer.from(json, 'utf8').toString('base64');\n return base64;\n}\n\nexport class DefaultEntitiesCatalog implements EntitiesCatalog {\n private readonly database: Knex;\n private readonly logger: LoggerService;\n private readonly stitcher: Stitcher;\n private readonly enableRelationsCompatibility: boolean;\n\n constructor(options: {\n database: Knex;\n logger: LoggerService;\n stitcher: Stitcher;\n enableRelationsCompatibility?: boolean;\n }) {\n this.database = options.database;\n this.logger = options.logger;\n this.stitcher = options.stitcher;\n this.enableRelationsCompatibility = Boolean(\n options.enableRelationsCompatibility,\n );\n }\n\n async entities(request?: EntitiesRequest): Promise<EntitiesResponse> {\n const db = this.database;\n const { limit, offset } = parsePagination(request?.pagination);\n\n let entitiesQuery =\n db<DbFinalEntitiesRow>('final_entities').select('final_entities.*');\n\n request?.order?.forEach(({ field }, index) => {\n const alias = `order_${index}`;\n entitiesQuery = entitiesQuery.leftOuterJoin(\n { [alias]: 'search' },\n function search(inner) {\n inner\n .on(`${alias}.entity_id`, 'final_entities.entity_id')\n .andOn(`${alias}.key`, db.raw('?', [field]));\n },\n );\n });\n\n entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity');\n\n if (request?.filter) {\n entitiesQuery = applyEntityFilterToQuery({\n filter: request.filter,\n targetQuery: entitiesQuery,\n onEntityIdField: 'final_entities.entity_id',\n knex: db,\n });\n }\n\n request?.order?.forEach(({ order }, index) => {\n if (db.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order, nulls: 'last' },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n entitiesQuery = entitiesQuery.orderBy([\n { column: `order_${index}.value`, order: undefined, nulls: 'last' },\n { column: `order_${index}.value`, order },\n ]);\n }\n });\n\n if (!request?.order) {\n entitiesQuery = entitiesQuery.orderBy('final_entities.entity_ref', 'asc'); // default sort\n } else {\n entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort\n }\n\n if (limit !== undefined) {\n entitiesQuery = entitiesQuery.limit(limit + 1);\n }\n if (offset !== undefined) {\n entitiesQuery = entitiesQuery.offset(offset);\n }\n\n let rows = await entitiesQuery;\n let pageInfo: DbPageInfo;\n if (limit === undefined || rows.length <= limit) {\n pageInfo = { hasNextPage: false };\n } else {\n rows = rows.slice(0, -1);\n pageInfo = {\n hasNextPage: true,\n endCursor: stringifyPagination({\n limit,\n offset: (offset ?? 0) + limit,\n }),\n };\n }\n\n return {\n entities: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n this.enableRelationsCompatibility\n ? e => {\n expandLegacyCompoundRelationsInEntity(e);\n if (request?.fields) {\n return request.fields(e);\n }\n return e;\n }\n : request?.fields,\n ),\n pageInfo,\n };\n }\n\n async entitiesBatch(\n request: EntitiesBatchRequest,\n ): Promise<EntitiesBatchResponse> {\n const lookup = new Map<string, string>();\n\n for (const chunk of lodashChunk(request.entityRefs, 200)) {\n let query = this.database<DbFinalEntitiesRow>('final_entities')\n .select({\n entityRef: 'final_entities.entity_ref',\n entity: 'final_entities.final_entity',\n })\n .whereIn('final_entities.entity_ref', chunk);\n\n if (request?.filter || request?.query) {\n query = applyEntityFilterToQuery({\n filter: request.filter,\n query: request.query,\n targetQuery: query,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n for (const row of await query) {\n lookup.set(row.entityRef, row.entity ? row.entity : null);\n }\n }\n\n const items = request.entityRefs.map(ref => lookup.get(ref) ?? null);\n\n return { items: processRawEntitiesResult(items, request.fields) };\n }\n\n async queryEntities(\n request: QueryEntitiesRequest,\n ): Promise<QueryEntitiesResponse> {\n const limit = request.limit ?? DEFAULT_LIMIT;\n\n const cursor: Omit<Cursor, 'orderFieldValues'> & {\n orderFieldValues?: (string | null)[];\n skipTotalItems: boolean;\n } = {\n orderFields: [],\n isPrevious: false,\n ...parseCursorFromRequest(request),\n };\n\n // For performance reasons we invoke the count query only on the first\n // request. The result is then embedded into the cursor for subsequent\n // requests. Threfore this can be undefined here, but will then get\n // populated further down.\n const shouldComputeTotalItems =\n cursor.totalItems === undefined && !cursor.skipTotalItems;\n const isFetchingBackwards = cursor.isPrevious;\n\n if (cursor.orderFields.length > 1) {\n this.logger.warn(`Only one sort field is supported, ignoring the rest`);\n }\n\n const sortField = cursor.orderFields.at(0);\n\n // The first part of the query builder is a subquery that applies all of the\n // filtering.\n const dbQuery = this.database.with(\n 'filtered',\n ['entity_id', 'final_entity', ...(sortField ? ['value'] : [])],\n inner => {\n inner\n .from<DbFinalEntitiesRow>('final_entities')\n .whereNotNull('final_entity');\n\n if (sortField) {\n inner\n .distinct()\n .leftOuterJoin('search', qb =>\n qb\n .on('search.entity_id', 'final_entities.entity_id')\n .andOnVal('search.key', sortField.field),\n )\n .select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n value: 'search.value',\n });\n } else {\n inner.select({\n entity_id: 'final_entities.entity_id',\n final_entity: 'final_entities.final_entity',\n });\n }\n\n // Add regular filters and/or predicate query, if given\n if (cursor.filter || cursor.query) {\n applyEntityFilterToQuery({\n filter: cursor.filter,\n query: cursor.query,\n targetQuery: inner,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n }\n\n // Add full text search filters, if given\n const normalizedFullTextFilterTerm =\n cursor.fullTextFilter?.term?.trim();\n const textFilterFields = cursor.fullTextFilter?.fields ?? [\n sortField?.field || 'metadata.uid',\n ];\n if (normalizedFullTextFilterTerm) {\n if (\n textFilterFields.length === 1 &&\n textFilterFields[0] === sortField?.field\n ) {\n // If there is one item, apply the like query to the top level query which is already\n // filtered based on the singular sortField.\n inner.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`,\n );\n } else {\n const matchQuery = this.database<DbSearchRow>('search')\n .select('search.entity_id')\n // textFilterFields must be lowercased to match searchable keys in database, i.e. spec.profile.displayName -> spec.profile.displayname\n .whereIn(\n 'search.key',\n textFilterFields.map(field => field.toLocaleLowerCase('en-US')),\n )\n .andWhere(function keyFilter() {\n this.andWhereRaw(\n 'search.value like ?',\n `%${normalizedFullTextFilterTerm.toLocaleLowerCase(\n 'en-US',\n )}%`,\n );\n });\n inner.andWhere('final_entities.entity_id', 'in', matchQuery);\n }\n }\n },\n );\n\n // Only pay the cost of counting the number of items if needed\n if (shouldComputeTotalItems) {\n // Note the intentional cross join here. The filtered_count dataset is\n // always exactly one row, so it won't grow the result unnecessarily. But\n // it's also important that there IS at least one row, because even if the\n // filtered dataset is empty, we still want to know the total number of\n // items.\n dbQuery\n .with('filtered_count', ['count'], inner =>\n inner.from('filtered').count('*', { as: 'count' }),\n )\n .fromRaw('filtered_count, filtered')\n .select('count', 'filtered.*');\n } else {\n dbQuery.from('filtered').select('*');\n }\n\n const isOrderingDescending = sortField?.order === 'desc';\n\n // Move forward (or backward) in the set to the correct cursor position\n if (cursor.orderFieldValues) {\n if (cursor.orderFieldValues.length === 2) {\n // The first will be the sortField value, the second the entity_id\n const [first, second] = cursor.orderFieldValues;\n dbQuery.andWhere(function nested() {\n this.where(\n 'filtered.value',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n first,\n )\n .orWhere('filtered.value', '=', first)\n .andWhere(\n 'filtered.entity_id',\n isFetchingBackwards !== isOrderingDescending ? '<' : '>',\n second,\n );\n });\n } else if (cursor.orderFieldValues.length === 1) {\n // This will be the entity_id\n const [first] = cursor.orderFieldValues;\n dbQuery.andWhere('entity_id', isFetchingBackwards ? '<' : '>', first);\n }\n }\n\n // Add the ordering\n let order = sortField?.order ?? 'asc';\n if (isFetchingBackwards) {\n order = invertOrder(order);\n }\n if (this.database.client.config.client === 'pg') {\n // pg correctly orders by the column value and handling nulls in one go\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order,\n nulls: 'last',\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n } else {\n // sqlite and mysql translate the above statement ONLY into \"order by (value is null) asc\"\n // no matter what the order is, for some reason, so we have to manually add back the statement\n // that translates to \"order by value <order>\" while avoiding to give an order\n dbQuery.orderBy([\n ...(sortField\n ? [\n {\n column: 'filtered.value',\n order: undefined,\n nulls: 'last',\n },\n {\n column: 'filtered.value',\n order,\n },\n ]\n : []),\n {\n column: 'filtered.entity_id',\n order,\n },\n ]);\n }\n\n // Apply a manually set initial offset\n if (\n isQueryEntitiesInitialRequest(request) &&\n request.offset !== undefined\n ) {\n dbQuery.offset(request.offset);\n }\n // fetch an extra item to check if there are more items.\n dbQuery.limit(isFetchingBackwards ? limit : limit + 1);\n\n const rows = shouldComputeTotalItems || limit > 0 ? await dbQuery : [];\n\n let totalItems: number;\n if (cursor.totalItems !== undefined) {\n totalItems = cursor.totalItems;\n } else if (cursor.skipTotalItems) {\n totalItems = 0;\n } else if (rows.length) {\n totalItems = Number(rows[0].count);\n } else {\n totalItems = 0;\n }\n\n if (isFetchingBackwards) {\n rows.reverse();\n }\n const hasMoreResults =\n limit > 0 && (isFetchingBackwards || rows.length > limit);\n\n // discard the extra item only when fetching forward.\n if (rows.length > limit) {\n rows.length -= 1;\n }\n\n const isInitialRequest = cursor.firstSortFieldValues === undefined;\n\n const firstRow = rows[0];\n const lastRow = rows[rows.length - 1];\n\n const firstSortFieldValues =\n cursor.firstSortFieldValues || sortFieldsFromRow(firstRow, sortField);\n\n const nextCursor: Cursor | undefined = hasMoreResults\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(lastRow, sortField),\n firstSortFieldValues,\n isPrevious: false,\n totalItems,\n }\n : undefined;\n\n const prevCursor: Cursor | undefined =\n !isInitialRequest &&\n rows.length > 0 &&\n !isEqual(\n sortFieldsFromRow(firstRow, sortField),\n cursor.firstSortFieldValues,\n )\n ? {\n ...cursor,\n orderFieldValues: sortFieldsFromRow(firstRow, sortField),\n firstSortFieldValues: cursor.firstSortFieldValues,\n isPrevious: true,\n totalItems,\n }\n : undefined;\n\n return {\n items: processRawEntitiesResult(\n rows.map(r => r.final_entity!),\n request.fields,\n ),\n pageInfo: {\n ...(!!prevCursor && { prevCursor }),\n ...(!!nextCursor && { nextCursor }),\n },\n totalItems,\n };\n }\n\n async removeEntityByUid(uid: string): Promise<void> {\n const relationPeerRefs = await this.database.transaction(async tx => {\n const dbConfig = tx.client.config;\n\n // Clear the hashed state of the immediate parents of the deleted entity.\n // This makes sure that when they get reprocessed, their output is written\n // down again. The reason for wanting to do this, is that if the user\n // deletes entities that ARE still emitted by the parent, the parent\n // processing will still generate the same output hash as always, which\n // means it'll never try to write down the children again (it assumes that\n // they already exist). This means that without the code below, the database\n // never \"heals\" from accidental deletes.\n if (dbConfig.client.includes('mysql')) {\n // MySQL doesn't support the syntax we need to do this in a single query,\n // http://dev.mysql.com/doc/refman/5.6/en/update.html\n const results = await tx<DbRefreshStateRow>('refresh_state')\n .select('entity_id')\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n await tx<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: tx.fn.now(),\n })\n .whereIn(\n 'entity_id',\n results.map(key => key.entity_id),\n );\n } else {\n await tx<DbRefreshStateRow>('refresh_state')\n .update({\n result_hash: 'child-was-deleted',\n next_update_at: tx.fn.now(),\n })\n .whereIn('entity_ref', function parents(builder) {\n return builder\n .from<DbRefreshStateRow>('refresh_state')\n .innerJoin<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n {\n 'refresh_state_references.target_entity_ref':\n 'refresh_state.entity_ref',\n },\n )\n .where('refresh_state.entity_id', '=', uid)\n .select('refresh_state_references.source_entity_ref');\n });\n }\n\n const relationPeers = await tx\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.target_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.target_entity_ref' })\n .union(other =>\n other\n .from<DbRelationsRow>('relations')\n .innerJoin<DbRefreshStateRow>('refresh_state', {\n 'refresh_state.entity_ref': 'relations.source_entity_ref',\n })\n .where('relations.originating_entity_id', '=', uid)\n .andWhere('refresh_state.entity_id', '!=', uid)\n .select({ ref: 'relations.source_entity_ref' }),\n );\n\n await tx<DbRefreshStateRow>('refresh_state')\n .where('entity_id', uid)\n .delete();\n\n return new Set(relationPeers.map(p => p.ref));\n });\n\n if (relationPeerRefs.size > 0) {\n await this.stitcher.stitch({\n entityRefs: relationPeerRefs,\n });\n }\n }\n\n async entityAncestry(rootRef: string): Promise<EntityAncestryResponse> {\n const [rootRow] = await this.database<DbFinalEntitiesRow>('final_entities')\n .where('final_entities.entity_ref', '=', rootRef)\n .select({\n entityJson: 'final_entities.final_entity',\n });\n\n if (!rootRow) {\n throw new NotFoundError(`No such entity ${rootRef}`);\n }\n\n const rootEntity = JSON.parse(rootRow.entityJson) as Entity;\n const seenEntityRefs = new Set<string>();\n const todo = new Array<Entity>();\n const items = new Array<{ entity: Entity; parentEntityRefs: string[] }>();\n\n for (\n let current: Entity | undefined = rootEntity;\n current;\n current = todo.pop()\n ) {\n const currentRef = stringifyEntityRef(current);\n seenEntityRefs.add(currentRef);\n\n const parentRows = await this.database<DbRefreshStateReferencesRow>(\n 'refresh_state_references',\n )\n .innerJoin<DbFinalEntitiesRow>('final_entities', {\n 'refresh_state_references.source_entity_ref':\n 'final_entities.entity_ref',\n })\n .where('refresh_state_references.target_entity_ref', '=', currentRef)\n .select({\n parentEntityRef: 'final_entities.entity_ref',\n parentEntityJson: 'final_entities.final_entity',\n });\n\n const parentRefs: string[] = [];\n for (const { parentEntityRef, parentEntityJson } of parentRows) {\n parentRefs.push(parentEntityRef);\n if (!seenEntityRefs.has(parentEntityRef)) {\n seenEntityRefs.add(parentEntityRef);\n todo.push(JSON.parse(parentEntityJson));\n }\n }\n\n items.push({\n entity: current,\n parentEntityRefs: parentRefs,\n });\n }\n\n return {\n rootEntityRef: stringifyEntityRef(rootEntity),\n items,\n };\n }\n\n async facets(request: EntityFacetsRequest): Promise<EntityFacetsResponse> {\n const query = this.database<DbSearchRow>('search')\n .whereIn(\n 'search.key',\n request.facets.map(f => f.toLocaleLowerCase('en-US')),\n )\n .whereNotNull('search.original_value')\n .select({\n facet: 'search.key',\n value: 'search.original_value',\n count: this.database.raw('count(DISTINCT search.entity_id)'),\n })\n .groupBy(['search.key', 'search.original_value']);\n\n if (request.filter || request.query) {\n // Build a subquery that finds matching entity IDs via\n // final_entities, so that the EXISTS-based filters correlate\n // against one-row-per-entity rather than the much larger search\n // table. The whereNotNull guard on final_entity excludes\n // not-yet-stitched (or future tombstoned) entities.\n const entityIdSubquery = this.database('final_entities')\n .select('final_entities.entity_id')\n .whereNotNull('final_entities.final_entity');\n\n applyEntityFilterToQuery({\n filter: request.filter,\n query: request.query,\n targetQuery: entityIdSubquery,\n onEntityIdField: 'final_entities.entity_id',\n knex: this.database,\n });\n\n query.whereIn('search.entity_id', entityIdSubquery);\n }\n\n const rows = await query;\n\n const facets: EntityFacetsResponse['facets'] = {};\n for (const facet of request.facets) {\n const facetLowercase = facet.toLocaleLowerCase('en-US');\n facets[facet] = rows\n .filter(row => row.facet === facetLowercase)\n .map(row => ({\n value: String(row.value),\n count: Number(row.count),\n }));\n }\n\n return { facets };\n }\n}\n\nfunction parseCursorFromRequest(\n request?: QueryEntitiesRequest,\n): Partial<Cursor> & { skipTotalItems: boolean } {\n if (isQueryEntitiesInitialRequest(request)) {\n const {\n filter,\n query,\n orderFields: sortFields = [],\n fullTextFilter,\n skipTotalItems = false,\n } = request;\n return {\n filter,\n query,\n orderFields: sortFields,\n fullTextFilter,\n skipTotalItems,\n };\n }\n if (isQueryEntitiesCursorRequest(request)) {\n return {\n ...request.cursor,\n // Doesn't matter here\n skipTotalItems: false,\n };\n }\n return {\n skipTotalItems: false,\n };\n}\n\nfunction invertOrder(order: EntityOrder['order']) {\n return order === 'asc' ? 'desc' : 'asc';\n}\n\nfunction sortFieldsFromRow(\n row: DbSearchRow & DbFinalEntitiesRow,\n sortField?: EntityOrder | undefined,\n) {\n return sortField ? [row?.value, row?.entity_id] : [row?.entity_id];\n}\n"],"names":["InputError","applyEntityFilterToQuery","processRawEntitiesResult","expandLegacyCompoundRelationsInEntity","lodashChunk","isQueryEntitiesInitialRequest","isEqual","NotFoundError","stringifyEntityRef","isQueryEntitiesCursorRequest"],"mappings":"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"}
|