Rename DescriptorEnvelope to Entity
This commit is contained in:
@@ -15,20 +15,20 @@
|
||||
*/
|
||||
|
||||
import { Database } from '../database';
|
||||
import { DescriptorEnvelope } from '../ingestion/types';
|
||||
import { Entity } from '../ingestion/types';
|
||||
import { EntitiesCatalog, EntityFilters } from './types';
|
||||
|
||||
export class DatabaseEntitiesCatalog implements EntitiesCatalog {
|
||||
constructor(private readonly database: Database) {}
|
||||
|
||||
async entities(filters?: EntityFilters): Promise<DescriptorEnvelope[]> {
|
||||
async entities(filters?: EntityFilters): Promise<Entity[]> {
|
||||
const items = await this.database.transaction(tx =>
|
||||
this.database.entities(tx, filters),
|
||||
);
|
||||
return items.map(i => i.entity);
|
||||
}
|
||||
|
||||
async entityByUid(uid: string): Promise<DescriptorEnvelope | undefined> {
|
||||
async entityByUid(uid: string): Promise<Entity | undefined> {
|
||||
const matches = await this.database.transaction(tx =>
|
||||
this.database.entities(tx, [{ key: 'uid', values: [uid] }]),
|
||||
);
|
||||
@@ -40,7 +40,7 @@ export class DatabaseEntitiesCatalog implements EntitiesCatalog {
|
||||
kind: string,
|
||||
name: string,
|
||||
namespace: string | undefined,
|
||||
): Promise<DescriptorEnvelope | undefined> {
|
||||
): Promise<Entity | undefined> {
|
||||
const matches = await this.database.transaction(tx =>
|
||||
this.database.entities(tx, [
|
||||
{ key: 'kind', values: [kind] },
|
||||
|
||||
@@ -13,13 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import knex from 'knex';
|
||||
import path from 'path';
|
||||
|
||||
import { Database } from '../database';
|
||||
import { ReaderOutput } from '../ingestion/types';
|
||||
import { getVoidLogger } from '@backstage/backend-common';
|
||||
import { DatabaseLocationsCatalog } from './DatabaseLocationsCatalog';
|
||||
|
||||
describe('DatabaseLocationsCatalog', () => {
|
||||
const database = knex({
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
|
||||
import { Database } from '../database';
|
||||
import { AddLocation, Location, LocationsCatalog } from './types';
|
||||
import { LocationReader } from '../ingestion';
|
||||
import { AddLocation, Location, LocationsCatalog } from './types';
|
||||
|
||||
export class DatabaseLocationsCatalog implements LocationsCatalog {
|
||||
constructor(
|
||||
|
||||
@@ -16,21 +16,21 @@
|
||||
|
||||
import { NotFoundError } from '@backstage/backend-common';
|
||||
import lodash from 'lodash';
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
import { EntitiesCatalog } from './types';
|
||||
|
||||
export class StaticEntitiesCatalog implements EntitiesCatalog {
|
||||
private _entities: DescriptorEnvelope[];
|
||||
private _entities: Entity[];
|
||||
|
||||
constructor(entities: DescriptorEnvelope[]) {
|
||||
constructor(entities: Entity[]) {
|
||||
this._entities = entities;
|
||||
}
|
||||
|
||||
async entities(): Promise<DescriptorEnvelope[]> {
|
||||
async entities(): Promise<Entity[]> {
|
||||
return lodash.cloneDeep(this._entities);
|
||||
}
|
||||
|
||||
async entityByUid(uid: string): Promise<DescriptorEnvelope | undefined> {
|
||||
async entityByUid(uid: string): Promise<Entity | undefined> {
|
||||
const item = this._entities.find(e => uid === e.metadata?.uid);
|
||||
if (!item) {
|
||||
throw new NotFoundError('Entity cannot be found');
|
||||
@@ -42,7 +42,7 @@ export class StaticEntitiesCatalog implements EntitiesCatalog {
|
||||
kind: string,
|
||||
name: string,
|
||||
namespace: string | undefined,
|
||||
): Promise<DescriptorEnvelope | undefined> {
|
||||
): Promise<Entity | undefined> {
|
||||
const item = this._entities.find(
|
||||
e =>
|
||||
kind === e.kind &&
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
|
||||
//
|
||||
// Entities
|
||||
@@ -28,13 +28,13 @@ export type EntityFilter = {
|
||||
export type EntityFilters = EntityFilter[];
|
||||
|
||||
export type EntitiesCatalog = {
|
||||
entities(filters?: EntityFilters): Promise<DescriptorEnvelope[]>;
|
||||
entityByUid(uid: string): Promise<DescriptorEnvelope | undefined>;
|
||||
entities(filters?: EntityFilters): Promise<Entity[]>;
|
||||
entityByUid(uid: string): Promise<Entity | undefined>;
|
||||
entityByName(
|
||||
kind: string,
|
||||
namespace: string | undefined,
|
||||
name: string,
|
||||
): Promise<DescriptorEnvelope | undefined>;
|
||||
): Promise<Entity | undefined>;
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from '@backstage/backend-common';
|
||||
import Knex from 'knex';
|
||||
import path from 'path';
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
import { Database } from './Database';
|
||||
import {
|
||||
AddDatabaseLocation,
|
||||
@@ -247,8 +247,8 @@ describe('Database', () => {
|
||||
describe('entities', () => {
|
||||
it('can get all entities with empty filters list', async () => {
|
||||
const catalog = new Database(database, getVoidLogger());
|
||||
const e1: DescriptorEnvelope = { apiVersion: 'a', kind: 'b' };
|
||||
const e2: DescriptorEnvelope = {
|
||||
const e1: Entity = { apiVersion: 'a', kind: 'b' };
|
||||
const e2: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'b',
|
||||
spec: { c: null },
|
||||
@@ -271,7 +271,7 @@ describe('Database', () => {
|
||||
|
||||
it('can get all specific entities for matching filters (naive case)', async () => {
|
||||
const catalog = new Database(database, getVoidLogger());
|
||||
const entities: DescriptorEnvelope[] = [
|
||||
const entities: Entity[] = [
|
||||
{ apiVersion: 'a', kind: 'b' },
|
||||
{
|
||||
apiVersion: 'a',
|
||||
@@ -305,7 +305,7 @@ describe('Database', () => {
|
||||
|
||||
it('can get all specific entities for matching filters with nulls (both missing and literal null value)', async () => {
|
||||
const catalog = new Database(database, getVoidLogger());
|
||||
const entities: DescriptorEnvelope[] = [
|
||||
const entities: Entity[] = [
|
||||
{ apiVersion: 'a', kind: 'b' },
|
||||
{
|
||||
apiVersion: 'a',
|
||||
|
||||
@@ -24,7 +24,7 @@ import lodash from 'lodash';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Logger } from 'winston';
|
||||
import { EntityFilters } from '../catalog';
|
||||
import { DescriptorEnvelope, EntityMeta } from '../ingestion';
|
||||
import { Entity, EntityMeta } from '../ingestion';
|
||||
import { buildEntitySearch } from './search';
|
||||
import {
|
||||
AddDatabaseLocation,
|
||||
@@ -54,9 +54,7 @@ function serializeMetadata(metadata: EntityMeta | undefined): string | null {
|
||||
return JSON.stringify(getStrippedMetadata(metadata));
|
||||
}
|
||||
|
||||
function serializeSpec(
|
||||
spec: DescriptorEnvelope['spec'],
|
||||
): DbEntitiesRow['spec'] {
|
||||
function serializeSpec(spec: Entity['spec']): DbEntitiesRow['spec'] {
|
||||
if (!spec) {
|
||||
return null;
|
||||
}
|
||||
@@ -66,7 +64,7 @@ function serializeSpec(
|
||||
|
||||
function toEntityRow(
|
||||
locationId: string | undefined,
|
||||
entity: DescriptorEnvelope,
|
||||
entity: Entity,
|
||||
): DbEntitiesRow {
|
||||
return {
|
||||
id: entity.metadata!.uid!,
|
||||
@@ -83,7 +81,7 @@ function toEntityRow(
|
||||
}
|
||||
|
||||
function toEntityResponse(row: DbEntitiesRow): DbEntityResponse {
|
||||
const entity: DescriptorEnvelope = {
|
||||
const entity: Entity = {
|
||||
apiVersion: row.api_version,
|
||||
kind: row.kind,
|
||||
metadata: {
|
||||
@@ -94,7 +92,7 @@ function toEntityResponse(row: DbEntitiesRow): DbEntityResponse {
|
||||
};
|
||||
|
||||
if (row.metadata) {
|
||||
const metadata = JSON.parse(row.metadata) as DescriptorEnvelope['metadata'];
|
||||
const metadata = JSON.parse(row.metadata) as Entity['metadata'];
|
||||
entity.metadata = { ...entity.metadata, ...metadata };
|
||||
}
|
||||
|
||||
@@ -127,7 +125,9 @@ function generateUid(): string {
|
||||
}
|
||||
|
||||
function generateEtag(): string {
|
||||
return Buffer.from(uuidv4(), 'utf8').toString('base64').replace(/[^\w]/g, '');
|
||||
return Buffer.from(uuidv4(), 'utf8')
|
||||
.toString('base64')
|
||||
.replace(/[^\w]/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,7 +374,9 @@ export class Database {
|
||||
target,
|
||||
});
|
||||
|
||||
return (await tx<DbLocationsRow>('locations').where({ id }).select())![0];
|
||||
return (await tx<DbLocationsRow>('locations')
|
||||
.where({ id })
|
||||
.select())![0];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -422,7 +424,7 @@ export class Database {
|
||||
private async updateEntitiesSearch(
|
||||
tx: Knex.Transaction<any, any>,
|
||||
entityId: string,
|
||||
data: DescriptorEnvelope,
|
||||
data: Entity,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const entries = buildEntitySearch(entityId, data);
|
||||
|
||||
@@ -19,8 +19,8 @@ import lodash from 'lodash';
|
||||
import path from 'path';
|
||||
import { Logger } from 'winston';
|
||||
import {
|
||||
DescriptorEnvelope,
|
||||
DescriptorParser,
|
||||
Entity,
|
||||
LocationReader,
|
||||
ParserError,
|
||||
} from '../ingestion';
|
||||
@@ -129,7 +129,7 @@ export class DatabaseManager {
|
||||
private static async refreshSingleEntity(
|
||||
database: Database,
|
||||
locationId: string,
|
||||
entity: DescriptorEnvelope,
|
||||
entity: Entity,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
const { kind } = entity;
|
||||
@@ -163,10 +163,7 @@ export class DatabaseManager {
|
||||
});
|
||||
}
|
||||
|
||||
private static entitiesAreEqual(
|
||||
first: DescriptorEnvelope,
|
||||
second: DescriptorEnvelope,
|
||||
) {
|
||||
private static entitiesAreEqual(first: Entity, second: Entity) {
|
||||
const firstClone = lodash.cloneDeep(first);
|
||||
const secondClone = lodash.cloneDeep(second);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
import { buildEntitySearch, visitEntityPart } from './search';
|
||||
import { DbEntitiesSearchRow } from './types';
|
||||
|
||||
@@ -99,7 +99,7 @@ describe('search', () => {
|
||||
|
||||
describe('buildEntitySearch', () => {
|
||||
it('adds special keys even if missing', () => {
|
||||
const input: DescriptorEnvelope = {
|
||||
const input: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'b',
|
||||
};
|
||||
@@ -116,7 +116,7 @@ describe('search', () => {
|
||||
});
|
||||
|
||||
it('adds prefix-stripped versions', () => {
|
||||
const input: DescriptorEnvelope = {
|
||||
const input: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'b',
|
||||
metadata: {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
import { DbEntitiesSearchRow } from './types';
|
||||
|
||||
// Search entries that start with these prefixes, also get a shorthand without
|
||||
@@ -119,7 +119,7 @@ export function visitEntityPart(
|
||||
*/
|
||||
export function buildEntitySearch(
|
||||
entityId: string,
|
||||
entity: DescriptorEnvelope,
|
||||
entity: Entity,
|
||||
): DbEntitiesSearchRow[] {
|
||||
// Start with some special keys that are always present because you want to
|
||||
// be able to easily search for null specifically
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
|
||||
export type DbEntitiesRow = {
|
||||
id: string;
|
||||
@@ -32,12 +32,12 @@ export type DbEntitiesRow = {
|
||||
|
||||
export type DbEntityRequest = {
|
||||
locationId?: string;
|
||||
entity: DescriptorEnvelope;
|
||||
entity: Entity;
|
||||
};
|
||||
|
||||
export type DbEntityResponse = {
|
||||
locationId?: string;
|
||||
entity: DescriptorEnvelope;
|
||||
entity: Entity;
|
||||
};
|
||||
|
||||
export type DbEntitiesSearchRow = {
|
||||
|
||||
@@ -17,12 +17,7 @@
|
||||
import { makeValidator } from '../validation';
|
||||
import { ComponentDescriptorV1beta1Parser } from './descriptors/ComponentDescriptorV1beta1Parser';
|
||||
import { DescriptorEnvelopeParser } from './descriptors/DescriptorEnvelopeParser';
|
||||
import {
|
||||
DescriptorEnvelope,
|
||||
DescriptorParser,
|
||||
KindParser,
|
||||
ParserError,
|
||||
} from './types';
|
||||
import { DescriptorParser, Entity, KindParser, ParserError } from './types';
|
||||
|
||||
export class DescriptorParsers implements DescriptorParser {
|
||||
static create(): DescriptorParser {
|
||||
@@ -37,7 +32,7 @@ export class DescriptorParsers implements DescriptorParser {
|
||||
private readonly kindParsers: KindParser[],
|
||||
) {}
|
||||
|
||||
async parse(descriptor: object): Promise<DescriptorEnvelope> {
|
||||
async parse(descriptor: object): Promise<Entity> {
|
||||
const envelope = await this.envelopeParser.parse(descriptor);
|
||||
for (const parser of this.kindParsers) {
|
||||
const parsed = await parser.tryParse(envelope);
|
||||
|
||||
+3
-5
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import { DescriptorEnvelope, KindParser, ParserError } from '../types';
|
||||
import { Entity, KindParser, ParserError } from '../types';
|
||||
|
||||
export interface ComponentDescriptorV1beta1 extends DescriptorEnvelope {
|
||||
export interface ComponentDescriptorV1beta1 extends Entity {
|
||||
spec: {
|
||||
type: string;
|
||||
};
|
||||
@@ -41,9 +41,7 @@ export class ComponentDescriptorV1beta1Parser implements KindParser {
|
||||
});
|
||||
}
|
||||
|
||||
async tryParse(
|
||||
envelope: DescriptorEnvelope,
|
||||
): Promise<DescriptorEnvelope | undefined> {
|
||||
async tryParse(envelope: Entity): Promise<Entity | undefined> {
|
||||
if (
|
||||
envelope.apiVersion !== 'backstage.io/v1beta1' ||
|
||||
envelope.kind !== 'Component'
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
import * as yup from 'yup';
|
||||
import { Validators } from '../../validation';
|
||||
import { DescriptorEnvelope } from '../types';
|
||||
import { Entity } from '../types';
|
||||
|
||||
/**
|
||||
* Parses some raw structured data as a descriptor envelope
|
||||
*/
|
||||
export class DescriptorEnvelopeParser {
|
||||
private schema: yup.Schema<DescriptorEnvelope>;
|
||||
private schema: yup.Schema<Entity>;
|
||||
|
||||
constructor(validators: Validators) {
|
||||
const apiVersionSchema = yup
|
||||
@@ -160,8 +160,8 @@ export class DescriptorEnvelopeParser {
|
||||
.noUnknown();
|
||||
}
|
||||
|
||||
async parse(data: any): Promise<DescriptorEnvelope> {
|
||||
let result: DescriptorEnvelope;
|
||||
async parse(data: any): Promise<Entity> {
|
||||
let result: Entity;
|
||||
try {
|
||||
result = await this.schema.validate(data, { strict: true });
|
||||
} catch (e) {
|
||||
|
||||
@@ -87,7 +87,7 @@ export type EntityMeta = {
|
||||
*
|
||||
* @see https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/
|
||||
*/
|
||||
export type DescriptorEnvelope = {
|
||||
export type Entity = {
|
||||
/**
|
||||
* The version of specification format for this particular entity that
|
||||
* this is written against.
|
||||
@@ -123,7 +123,7 @@ export type DescriptorParser = {
|
||||
* @returns A structure describing the parsed and validated descriptor
|
||||
* @throws An Error if the descriptor was malformed
|
||||
*/
|
||||
parse(descriptor: object): Promise<DescriptorEnvelope>;
|
||||
parse(descriptor: object): Promise<Entity>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -142,9 +142,7 @@ export type KindParser = {
|
||||
* @throws An Error if the type was handled and found to not be properly
|
||||
* formatted
|
||||
*/
|
||||
tryParse(
|
||||
envelope: DescriptorEnvelope,
|
||||
): Promise<DescriptorEnvelope | undefined>;
|
||||
tryParse(envelope: Entity): Promise<Entity | undefined>;
|
||||
};
|
||||
|
||||
export class ParserError extends Error {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { getVoidLogger } from '@backstage/backend-common';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { EntitiesCatalog, Location, LocationsCatalog } from '../catalog';
|
||||
import { DescriptorEnvelope } from '../ingestion';
|
||||
import { Entity } from '../ingestion';
|
||||
import { createRouter } from './router';
|
||||
|
||||
class MockEntitiesCatalog implements EntitiesCatalog {
|
||||
@@ -37,7 +37,7 @@ class MockLocationsCatalog implements LocationsCatalog {
|
||||
describe('createRouter', () => {
|
||||
describe('entities', () => {
|
||||
it('happy path: lists entities', async () => {
|
||||
const entities: DescriptorEnvelope[] = [{ apiVersion: 'a', kind: 'b' }];
|
||||
const entities: Entity[] = [{ apiVersion: 'a', kind: 'b' }];
|
||||
|
||||
const catalog = new MockEntitiesCatalog();
|
||||
catalog.entities.mockResolvedValueOnce(entities);
|
||||
@@ -76,7 +76,7 @@ describe('createRouter', () => {
|
||||
|
||||
describe('entityByUid', () => {
|
||||
it('can fetch entity by uid', async () => {
|
||||
const entity: DescriptorEnvelope = {
|
||||
const entity: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'b',
|
||||
metadata: {
|
||||
@@ -117,7 +117,7 @@ describe('createRouter', () => {
|
||||
|
||||
describe('entityByName', () => {
|
||||
it('can fetch entity by name', async () => {
|
||||
const entity: DescriptorEnvelope = {
|
||||
const entity: Entity = {
|
||||
apiVersion: 'a',
|
||||
kind: 'b',
|
||||
metadata: {
|
||||
@@ -190,7 +190,9 @@ describe('createRouter', () => {
|
||||
});
|
||||
|
||||
const app = express().use(router);
|
||||
const response = await request(app).post('/locations').send(location);
|
||||
const response = await request(app)
|
||||
.post('/locations')
|
||||
.send(location);
|
||||
|
||||
expect(response.status).toEqual(400);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user