@backstage/plugin-catalog-backend 1.6.0 → 1.7.0-next.0

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,30 @@
1
1
  # @backstage/plugin-catalog-backend
2
2
 
3
+ ## 1.7.0-next.0
4
+
5
+ ### Minor Changes
6
+
7
+ - f75bf76330: Implemented server side ordering in the entities endpoint
8
+
9
+ ### Patch Changes
10
+
11
+ - d136793ff0: Fixed an issue where internal references in the catalog would stick around for longer than expected, causing entities to not be deleted or orphaned as expected.
12
+ - Updated dependencies
13
+ - @backstage/catalog-model@1.1.5-next.0
14
+ - @backstage/plugin-scaffolder-common@1.2.4-next.0
15
+ - @backstage/catalog-client@1.3.0-next.0
16
+ - @backstage/backend-common@0.17.0
17
+ - @backstage/backend-plugin-api@0.2.0
18
+ - @backstage/config@1.0.5
19
+ - @backstage/errors@1.1.4
20
+ - @backstage/integration@1.4.1
21
+ - @backstage/types@1.0.2
22
+ - @backstage/plugin-catalog-common@1.0.10-next.0
23
+ - @backstage/plugin-catalog-node@1.3.1-next.0
24
+ - @backstage/plugin-permission-common@0.7.2
25
+ - @backstage/plugin-permission-node@0.7.2
26
+ - @backstage/plugin-search-common@1.2.0
27
+
3
28
  ## 1.6.0
4
29
 
5
30
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-catalog-backend",
3
- "version": "1.6.0",
3
+ "version": "1.7.0-next.0",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
package/dist/index.cjs.js CHANGED
@@ -1725,7 +1725,6 @@ class DefaultProcessingDatabase {
1725
1725
  async addUnprocessedEntities(txOpaque, options) {
1726
1726
  const tx = txOpaque;
1727
1727
  const stateReferences = new Array();
1728
- const conflictingStateReferences = new Array();
1729
1728
  for (const { entity, locationKey } of options.entities) {
1730
1729
  const entityRef = catalogModel.stringifyEntityRef(entity);
1731
1730
  const hash = generateStableHash$1(entity);
@@ -1759,10 +1758,9 @@ class DefaultProcessingDatabase {
1759
1758
  this.options.logger.warn(
1760
1759
  `Detected conflicting entityRef ${entityRef} already referenced by ${conflictingKey} and now also ${locationKey}`
1761
1760
  );
1762
- conflictingStateReferences.push(entityRef);
1763
1761
  }
1764
1762
  }
1765
- await tx("refresh_state_references").whereNotIn("target_entity_ref", conflictingStateReferences).andWhere({ source_entity_ref: options.sourceEntityRef }).delete();
1763
+ await tx("refresh_state_references").andWhere({ source_entity_ref: options.sourceEntityRef }).delete();
1766
1764
  await tx.batchInsert(
1767
1765
  "refresh_state_references",
1768
1766
  stateReferences.map((entityRef) => ({
@@ -2249,7 +2247,7 @@ function stringifyPagination(input) {
2249
2247
  return base64;
2250
2248
  }
2251
2249
  function addCondition(queryBuilder, db, filter, negate = false, entityIdField = "entity_id") {
2252
- const matchQuery = db("search").select(entityIdField).where({ key: filter.key.toLowerCase() }).andWhere(function keyFilter() {
2250
+ const matchQuery = db("search").select("search.entity_id").where({ key: filter.key.toLowerCase() }).andWhere(function keyFilter() {
2253
2251
  if (filter.values) {
2254
2252
  if (filter.values.length === 1) {
2255
2253
  this.where({ value: filter.values[0].toLowerCase() });
@@ -2305,12 +2303,41 @@ class DefaultEntitiesCatalog {
2305
2303
  this.stitcher = stitcher;
2306
2304
  }
2307
2305
  async entities(request) {
2306
+ var _a, _b;
2308
2307
  const db = this.database;
2309
2308
  let entitiesQuery = db("final_entities").select("final_entities.*");
2309
+ (_a = request == null ? void 0 : request.order) == null ? void 0 : _a.forEach(({ field }, index) => {
2310
+ const alias = `order_${index}`;
2311
+ entitiesQuery = entitiesQuery.leftOuterJoin(
2312
+ { [alias]: "search" },
2313
+ function search(inner) {
2314
+ inner.on(`${alias}.entity_id`, "final_entities.entity_id").andOn(`${alias}.key`, db.raw("?", [field]));
2315
+ }
2316
+ );
2317
+ });
2318
+ entitiesQuery = entitiesQuery.whereNotNull("final_entities.final_entity");
2310
2319
  if (request == null ? void 0 : request.filter) {
2311
- entitiesQuery = parseFilter(request.filter, entitiesQuery, db);
2320
+ entitiesQuery = parseFilter(
2321
+ request.filter,
2322
+ entitiesQuery,
2323
+ db,
2324
+ false,
2325
+ "final_entities.entity_id"
2326
+ );
2312
2327
  }
2313
- entitiesQuery = entitiesQuery.whereNotNull("final_entities.final_entity").orderBy("entity_id", "asc");
2328
+ (_b = request == null ? void 0 : request.order) == null ? void 0 : _b.forEach(({ order }, index) => {
2329
+ if (db.client.config.client === "pg") {
2330
+ entitiesQuery = entitiesQuery.orderBy([
2331
+ { column: `order_${index}.value`, order, nulls: "last" }
2332
+ ]);
2333
+ } else {
2334
+ entitiesQuery = entitiesQuery.orderBy([
2335
+ { column: `order_${index}.value`, order: void 0, nulls: "last" },
2336
+ { column: `order_${index}.value`, order }
2337
+ ]);
2338
+ }
2339
+ });
2340
+ entitiesQuery = entitiesQuery.orderBy("final_entities.entity_id", "asc");
2314
2341
  const { limit, offset } = parsePagination(request == null ? void 0 : request.pagination);
2315
2342
  if (limit !== void 0) {
2316
2343
  entitiesQuery = entitiesQuery.limit(limit + 1);
@@ -3282,6 +3309,22 @@ function parseEntityFacetParams(params) {
3282
3309
  throw new errors.InputError("Missing facet parameter");
3283
3310
  }
3284
3311
 
3312
+ function parseEntityOrderParams(params) {
3313
+ var _a;
3314
+ return (_a = parseStringsParam(params.order, "order")) == null ? void 0 : _a.map((item) => {
3315
+ const match = item.match(/^(asc|desc):(.+)$/);
3316
+ if (!match) {
3317
+ throw new errors.InputError(
3318
+ `Invalid order parameter "${item}", expected "<asc or desc>:<field name>"`
3319
+ );
3320
+ }
3321
+ return {
3322
+ order: match[1],
3323
+ field: match[2]
3324
+ };
3325
+ });
3326
+ }
3327
+
3285
3328
  async function requireRequestBody(req) {
3286
3329
  const contentType = req.header("content-type");
3287
3330
  if (!contentType) {
@@ -3353,6 +3396,7 @@ async function createRouter(options) {
3353
3396
  const { entities, pageInfo } = await entitiesCatalog.entities({
3354
3397
  filter: parseEntityFilterParams(req.query),
3355
3398
  fields: parseEntityTransformParams(req.query),
3399
+ order: parseEntityOrderParams(req.query),
3356
3400
  pagination: parseEntityPaginationParams(req.query),
3357
3401
  authorizationToken: getBearerToken(req.header("authorization"))
3358
3402
  });
@@ -4089,6 +4133,7 @@ class DefaultProviderDatabase {
4089
4133
  logger: this.options.logger
4090
4134
  });
4091
4135
  }
4136
+ await tx("refresh_state_references").where("target_entity_ref", entityRef).andWhere({ source_key: options.sourceKey }).delete();
4092
4137
  if (ok) {
4093
4138
  await tx(
4094
4139
  "refresh_state_references"