@backstage/plugin-catalog-backend 1.6.0-next.1 → 1.6.0-next.2
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 +28 -0
- package/alpha/package.json +1 -1
- package/dist/index.cjs.js +98 -60
- package/dist/index.cjs.js.map +1 -1
- package/migrations/20200511113813_init.js +2 -2
- package/migrations/20200702153613_entities.js +2 -1
- package/migrations/20200807120600_entitySearch.js +1 -1
- package/migrations/20200923104503_case_insensitivity.js +2 -2
- package/migrations/20201005122705_add_entity_full_name.js +4 -3
- package/migrations/20201006130744_entity_data_column.js +2 -1
- package/migrations/20201123205611_relations_table_uniq.js +2 -2
- package/migrations/20210302150147_refresh_state.js +35 -59
- package/migrations/20210622104022_refresh_state_location_key.js +1 -3
- package/migrations/20210925102509_add_refresh_state_input_hash.js +1 -1
- package/migrations/20220616202842_refresh_keys.js +4 -2
- package/migrations/20221109192547_search_add_original_value_column.js +51 -0
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend
|
|
2
2
|
|
|
3
|
+
## 1.6.0-next.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 3072ebfdd7: The search table also holds the original entity value now and the facets endpoint fetches the filtered entity data from the search table.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- c507aee8a2: Ensured typescript type checks in migration files.
|
|
12
|
+
- 884d749b14: Refactored to use `coreServices` from `@backstage/backend-plugin-api`.
|
|
13
|
+
- eacc8e2b55: Make it possible for entity providers to supply only entity refs, instead of full entities, in `delta` mutation deletions.
|
|
14
|
+
- 20a5161f04: Adds MySQL support for the catalog-backend
|
|
15
|
+
- Updated dependencies
|
|
16
|
+
- @backstage/plugin-catalog-node@1.3.0-next.2
|
|
17
|
+
- @backstage/backend-common@0.17.0-next.2
|
|
18
|
+
- @backstage/backend-plugin-api@0.2.0-next.2
|
|
19
|
+
- @backstage/plugin-search-common@1.2.0-next.2
|
|
20
|
+
- @backstage/plugin-permission-node@0.7.2-next.2
|
|
21
|
+
- @backstage/catalog-client@1.2.0-next.1
|
|
22
|
+
- @backstage/catalog-model@1.1.4-next.1
|
|
23
|
+
- @backstage/config@1.0.5-next.1
|
|
24
|
+
- @backstage/errors@1.1.4-next.1
|
|
25
|
+
- @backstage/integration@1.4.1-next.1
|
|
26
|
+
- @backstage/types@1.0.2-next.1
|
|
27
|
+
- @backstage/plugin-catalog-common@1.0.9-next.2
|
|
28
|
+
- @backstage/plugin-permission-common@0.7.2-next.1
|
|
29
|
+
- @backstage/plugin-scaffolder-common@1.2.3-next.1
|
|
30
|
+
|
|
3
31
|
## 1.6.0-next.1
|
|
4
32
|
|
|
5
33
|
### Minor Changes
|
package/alpha/package.json
CHANGED
package/dist/index.cjs.js
CHANGED
|
@@ -1517,6 +1517,7 @@ class DefaultProcessingDatabase {
|
|
|
1517
1517
|
refreshKeys,
|
|
1518
1518
|
locationKey
|
|
1519
1519
|
} = options;
|
|
1520
|
+
const configClient = tx.client.config.client;
|
|
1520
1521
|
const refreshResult = await tx("refresh_state").update({
|
|
1521
1522
|
processed_entity: JSON.stringify(processedEntity),
|
|
1522
1523
|
result_hash: resultHash,
|
|
@@ -1539,7 +1540,7 @@ class DefaultProcessingDatabase {
|
|
|
1539
1540
|
sourceEntityRef
|
|
1540
1541
|
});
|
|
1541
1542
|
let previousRelationRows;
|
|
1542
|
-
if (
|
|
1543
|
+
if (configClient.includes("sqlite3") || configClient.includes("mysql")) {
|
|
1543
1544
|
previousRelationRows = await tx("relations").select("*").where({ originating_entity_id: id });
|
|
1544
1545
|
await tx("relations").where({ originating_entity_id: id }).delete();
|
|
1545
1546
|
} else {
|
|
@@ -1868,16 +1869,20 @@ class DefaultProcessingDatabase {
|
|
|
1868
1869
|
next_update_at: tx.fn.now(),
|
|
1869
1870
|
last_discovery_at: tx.fn.now()
|
|
1870
1871
|
});
|
|
1871
|
-
if (
|
|
1872
|
+
if (tx.client.config.client.includes("pg")) {
|
|
1872
1873
|
query = query.onConflict("entity_ref").ignore();
|
|
1873
1874
|
}
|
|
1874
1875
|
const result = await query;
|
|
1875
1876
|
return result.rowCount === 1 || result.length === 1;
|
|
1876
1877
|
} catch (error) {
|
|
1877
|
-
if (
|
|
1878
|
+
if (!backendCommon.isDatabaseConflictError(error)) {
|
|
1879
|
+
throw error;
|
|
1880
|
+
} else {
|
|
1881
|
+
this.options.logger.debug(
|
|
1882
|
+
`Unable to insert a new refresh state row, ${error}`
|
|
1883
|
+
);
|
|
1878
1884
|
return false;
|
|
1879
1885
|
}
|
|
1880
|
-
throw error;
|
|
1881
1886
|
}
|
|
1882
1887
|
}
|
|
1883
1888
|
async checkLocationKeyConflict(tx, entityRef, locationKey) {
|
|
@@ -1906,7 +1911,7 @@ class DefaultProcessingDatabase {
|
|
|
1906
1911
|
deferred: e,
|
|
1907
1912
|
hash: generateStableHash$1(e.entity)
|
|
1908
1913
|
})),
|
|
1909
|
-
toRemove: options.removed.map((e) =>
|
|
1914
|
+
toRemove: options.removed.map((e) => e.entityRef)
|
|
1910
1915
|
};
|
|
1911
1916
|
}
|
|
1912
1917
|
const oldRefs = await tx(
|
|
@@ -2425,8 +2430,8 @@ function stringifyPagination(input) {
|
|
|
2425
2430
|
const base64 = Buffer.from(json, "utf8").toString("base64");
|
|
2426
2431
|
return base64;
|
|
2427
2432
|
}
|
|
2428
|
-
function addCondition(queryBuilder, db, filter, negate = false) {
|
|
2429
|
-
const matchQuery = db("search").select(
|
|
2433
|
+
function addCondition(queryBuilder, db, filter, negate = false, entityIdField = "entity_id") {
|
|
2434
|
+
const matchQuery = db("search").select(entityIdField).where({ key: filter.key.toLowerCase() }).andWhere(function keyFilter() {
|
|
2430
2435
|
if (filter.values) {
|
|
2431
2436
|
if (filter.values.length === 1) {
|
|
2432
2437
|
this.where({ value: filter.values[0].toLowerCase() });
|
|
@@ -2439,7 +2444,7 @@ function addCondition(queryBuilder, db, filter, negate = false) {
|
|
|
2439
2444
|
}
|
|
2440
2445
|
}
|
|
2441
2446
|
});
|
|
2442
|
-
queryBuilder.andWhere(
|
|
2447
|
+
queryBuilder.andWhere(entityIdField, negate ? "not in" : "in", matchQuery);
|
|
2443
2448
|
}
|
|
2444
2449
|
function isEntitiesSearchFilter(filter) {
|
|
2445
2450
|
return filter.hasOwnProperty("key");
|
|
@@ -2450,24 +2455,28 @@ function isOrEntityFilter(filter) {
|
|
|
2450
2455
|
function isNegationEntityFilter(filter) {
|
|
2451
2456
|
return filter.hasOwnProperty("not");
|
|
2452
2457
|
}
|
|
2453
|
-
function parseFilter(filter, query, db, negate = false) {
|
|
2458
|
+
function parseFilter(filter, query, db, negate = false, entityIdField = "entity_id") {
|
|
2454
2459
|
if (isEntitiesSearchFilter(filter)) {
|
|
2455
2460
|
return query.andWhere(function filterFunction() {
|
|
2456
|
-
addCondition(this, db, filter, negate);
|
|
2461
|
+
addCondition(this, db, filter, negate, entityIdField);
|
|
2457
2462
|
});
|
|
2458
2463
|
}
|
|
2459
2464
|
if (isNegationEntityFilter(filter)) {
|
|
2460
|
-
return parseFilter(filter.not, query, db, !negate);
|
|
2465
|
+
return parseFilter(filter.not, query, db, !negate, entityIdField);
|
|
2461
2466
|
}
|
|
2462
2467
|
return query[negate ? "andWhereNot" : "andWhere"](function filterFunction() {
|
|
2463
2468
|
var _a, _b;
|
|
2464
2469
|
if (isOrEntityFilter(filter)) {
|
|
2465
2470
|
for (const subFilter of (_a = filter.anyOf) != null ? _a : []) {
|
|
2466
|
-
this.orWhere(
|
|
2471
|
+
this.orWhere(
|
|
2472
|
+
(subQuery) => parseFilter(subFilter, subQuery, db, false, entityIdField)
|
|
2473
|
+
);
|
|
2467
2474
|
}
|
|
2468
2475
|
} else {
|
|
2469
2476
|
for (const subFilter of (_b = filter.allOf) != null ? _b : []) {
|
|
2470
|
-
this.andWhere(
|
|
2477
|
+
this.andWhere(
|
|
2478
|
+
(subQuery) => parseFilter(subFilter, subQuery, db, false, entityIdField)
|
|
2479
|
+
);
|
|
2471
2480
|
}
|
|
2472
2481
|
}
|
|
2473
2482
|
});
|
|
@@ -2551,14 +2560,36 @@ class DefaultEntitiesCatalog {
|
|
|
2551
2560
|
return { items };
|
|
2552
2561
|
}
|
|
2553
2562
|
async removeEntityByUid(uid) {
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2563
|
+
const dbConfig = this.database.client.config;
|
|
2564
|
+
if (dbConfig.client.includes("mysql")) {
|
|
2565
|
+
const results = await this.database("refresh_state").select("entity_id").whereIn("entity_ref", function parents(builder) {
|
|
2566
|
+
return builder.from("refresh_state").innerJoin(
|
|
2567
|
+
"refresh_state_references",
|
|
2568
|
+
{
|
|
2569
|
+
"refresh_state_references.target_entity_ref": "refresh_state.entity_ref"
|
|
2570
|
+
}
|
|
2571
|
+
).where("refresh_state.entity_id", "=", uid).select("refresh_state_references.source_entity_ref");
|
|
2572
|
+
});
|
|
2573
|
+
await this.database("refresh_state").update({
|
|
2574
|
+
result_hash: "child-was-deleted",
|
|
2575
|
+
next_update_at: this.database.fn.now()
|
|
2576
|
+
}).whereIn(
|
|
2577
|
+
"entity_id",
|
|
2578
|
+
results.map((key) => key.entity_id)
|
|
2579
|
+
);
|
|
2580
|
+
} else {
|
|
2581
|
+
await this.database("refresh_state").update({
|
|
2582
|
+
result_hash: "child-was-deleted",
|
|
2583
|
+
next_update_at: this.database.fn.now()
|
|
2584
|
+
}).whereIn("entity_ref", function parents(builder) {
|
|
2585
|
+
return builder.from("refresh_state").innerJoin(
|
|
2586
|
+
"refresh_state_references",
|
|
2587
|
+
{
|
|
2588
|
+
"refresh_state_references.target_entity_ref": "refresh_state.entity_ref"
|
|
2589
|
+
}
|
|
2590
|
+
).where("refresh_state.entity_id", "=", uid).select("refresh_state_references.source_entity_ref");
|
|
2591
|
+
});
|
|
2592
|
+
}
|
|
2562
2593
|
const relationPeers = await this.database.from("relations").innerJoin("refresh_state", {
|
|
2563
2594
|
"refresh_state.entity_ref": "relations.target_entity_ref"
|
|
2564
2595
|
}).where("relations.originating_entity_id", "=", uid).andWhere("refresh_state.entity_id", "!=", uid).select({ ref: "relations.target_entity_ref" }).union(
|
|
@@ -2614,32 +2645,17 @@ class DefaultEntitiesCatalog {
|
|
|
2614
2645
|
};
|
|
2615
2646
|
}
|
|
2616
2647
|
async facets(request) {
|
|
2617
|
-
const { entities } = await this.entities({
|
|
2618
|
-
filter: request.filter,
|
|
2619
|
-
authorizationToken: request.authorizationToken
|
|
2620
|
-
});
|
|
2621
2648
|
const facets = {};
|
|
2649
|
+
const db = this.database;
|
|
2622
2650
|
for (const facet of request.facets) {
|
|
2623
|
-
const
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
}).flatMap((field) => {
|
|
2632
|
-
if (typeof field === "string") {
|
|
2633
|
-
return [field];
|
|
2634
|
-
} else if (Array.isArray(field)) {
|
|
2635
|
-
return field.filter((i) => typeof i === "string");
|
|
2636
|
-
}
|
|
2637
|
-
return [];
|
|
2638
|
-
}).sort();
|
|
2639
|
-
const counts = lodash__default["default"].countBy(values, lodash__default["default"].identity);
|
|
2640
|
-
facets[facet] = Object.entries(counts).map(([value, count]) => ({
|
|
2641
|
-
value,
|
|
2642
|
-
count
|
|
2651
|
+
const dbQuery = db("search").join("final_entities", "search.entity_id", "final_entities.entity_id").where("search.key", facet.toLocaleLowerCase("en-US")).count("search.entity_id as count").select({ value: "search.original_value" }).groupBy("search.original_value");
|
|
2652
|
+
if (request == null ? void 0 : request.filter) {
|
|
2653
|
+
parseFilter(request.filter, dbQuery, db, false, "search.entity_id");
|
|
2654
|
+
}
|
|
2655
|
+
const result = await dbQuery;
|
|
2656
|
+
facets[facet] = result.map((data) => ({
|
|
2657
|
+
value: String(data.value),
|
|
2658
|
+
count: Number(data.count)
|
|
2643
2659
|
}));
|
|
2644
2660
|
}
|
|
2645
2661
|
return { facets };
|
|
@@ -3082,15 +3098,30 @@ function mapToRows(input, entityId) {
|
|
|
3082
3098
|
for (const { key: rawKey, value: rawValue } of input) {
|
|
3083
3099
|
const key = rawKey.toLocaleLowerCase("en-US");
|
|
3084
3100
|
if (rawValue === void 0 || rawValue === null) {
|
|
3085
|
-
result.push({
|
|
3101
|
+
result.push({
|
|
3102
|
+
entity_id: entityId,
|
|
3103
|
+
key,
|
|
3104
|
+
original_value: null,
|
|
3105
|
+
value: null
|
|
3106
|
+
});
|
|
3086
3107
|
} else {
|
|
3087
3108
|
const value = String(rawValue).toLocaleLowerCase("en-US");
|
|
3088
3109
|
if (key.length <= MAX_KEY_LENGTH) {
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3110
|
+
if (value.length <= MAX_VALUE_LENGTH) {
|
|
3111
|
+
result.push({
|
|
3112
|
+
entity_id: entityId,
|
|
3113
|
+
key,
|
|
3114
|
+
original_value: String(rawValue),
|
|
3115
|
+
value
|
|
3116
|
+
});
|
|
3117
|
+
} else {
|
|
3118
|
+
result.push({
|
|
3119
|
+
entity_id: entityId,
|
|
3120
|
+
key,
|
|
3121
|
+
original_value: null,
|
|
3122
|
+
value: null
|
|
3123
|
+
});
|
|
3124
|
+
}
|
|
3094
3125
|
}
|
|
3095
3126
|
}
|
|
3096
3127
|
}
|
|
@@ -3808,13 +3839,20 @@ class Connection {
|
|
|
3808
3839
|
});
|
|
3809
3840
|
} else if (mutation.type === "delta") {
|
|
3810
3841
|
this.check(mutation.added.map((e) => e.entity));
|
|
3811
|
-
this.check(
|
|
3842
|
+
this.check(
|
|
3843
|
+
mutation.removed.map((e) => "entity" in e ? e.entity : void 0).filter((e) => Boolean(e))
|
|
3844
|
+
);
|
|
3812
3845
|
await db.transaction(async (tx) => {
|
|
3813
3846
|
await db.replaceUnprocessedEntities(tx, {
|
|
3814
3847
|
sourceKey: this.config.id,
|
|
3815
3848
|
type: "delta",
|
|
3816
3849
|
added: mutation.added,
|
|
3817
|
-
removed: mutation.removed
|
|
3850
|
+
removed: mutation.removed.map(
|
|
3851
|
+
(r) => "entityRef" in r ? r : {
|
|
3852
|
+
entityRef: catalogModel.stringifyEntityRef(r.entity),
|
|
3853
|
+
locationKey: r.locationKey
|
|
3854
|
+
}
|
|
3855
|
+
)
|
|
3818
3856
|
});
|
|
3819
3857
|
});
|
|
3820
3858
|
}
|
|
@@ -4444,13 +4482,13 @@ const catalogPlugin = backendPluginApi.createBackendPlugin({
|
|
|
4444
4482
|
);
|
|
4445
4483
|
env.registerInit({
|
|
4446
4484
|
deps: {
|
|
4447
|
-
logger: backendPluginApi.
|
|
4448
|
-
config: backendPluginApi.
|
|
4449
|
-
reader: backendPluginApi.
|
|
4450
|
-
permissions: backendPluginApi.
|
|
4451
|
-
database: backendPluginApi.
|
|
4452
|
-
httpRouter: backendPluginApi.
|
|
4453
|
-
lifecycle: backendPluginApi.
|
|
4485
|
+
logger: backendPluginApi.coreServices.logger,
|
|
4486
|
+
config: backendPluginApi.coreServices.config,
|
|
4487
|
+
reader: backendPluginApi.coreServices.urlReader,
|
|
4488
|
+
permissions: backendPluginApi.coreServices.permissions,
|
|
4489
|
+
database: backendPluginApi.coreServices.database,
|
|
4490
|
+
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
4491
|
+
lifecycle: backendPluginApi.coreServices.lifecycle
|
|
4454
4492
|
},
|
|
4455
4493
|
async init({
|
|
4456
4494
|
logger,
|