Skip to content

Commit

Permalink
feat: model primaryIdentifier in database (#617)
Browse files Browse the repository at this point in the history
Adds the `primaryIdentifier` property from the resource spec to the
database. I can see the ensuing result in `db.json` after building.

It is typed as `string[]` because there are roughly 140 resources with >
1 `primaryIdentifiers`. There are also 7 resources with no
`primaryIdentifiers`.

---------

Signed-off-by: github-actions <github-actions@github.com>
Co-authored-by: github-actions <github-actions@github.com>
  • Loading branch information
kaizencc and github-actions authored Oct 23, 2023
1 parent 8d6dfa6 commit 8cb9f96
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 1 deletion.
3 changes: 3 additions & 0 deletions packages/@aws-cdk/service-spec-importers/src/db-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export class DbDiff {
name: diffScalar(a, b, 'name'),
scrutinizable: diffScalar(a, b, 'scrutinizable'),
tagInformation: diffField(a, b, 'tagInformation', jsonEq),
primaryIdentifier: collapseEmptyDiff(
diffList(a.primaryIdentifier ?? [], b.primaryIdentifier ?? [], (x, y) => x === y),
),
attributes: collapseEmptyDiff(diffMap(a.attributes, b.attributes, (x, y) => this.diffAttribute(x, y))),
properties: collapseEmptyDiff(diffMap(a.properties, b.properties, (x, y) => this.diffProperty(x, y))),
typeDefinitionDiff: this.diffResourceTypeDefinitions(a, b),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface LoadCloudFormationRegistryResourceOptions {
readonly report: ProblemReport;
readonly region?: string;
}

export function importCloudFormationRegistryResource(options: LoadCloudFormationRegistryResourceOptions) {
const { db, resource } = options;
const report = options.report.forAudience(ReportAudience.fromCloudFormationResource(resource.typeName));
Expand All @@ -25,6 +26,7 @@ export function importCloudFormationRegistryResource(options: LoadCloudFormation
const specBuilder = new SpecBuilder(db);
const resourceBuilder = specBuilder.resourceBuilder(resource.typeName, {
description: resource.description,
primaryIdentifier: resource.primaryIdentifier?.map((id) => id.slice(12)), // remove "/properties/" that reliably is included in each identifier
region: options.region,
});
const resourceFailure = failure.in(resource.typeName);
Expand Down
16 changes: 15 additions & 1 deletion packages/@aws-cdk/service-spec-importers/src/resource-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,41 @@ import {
} from '@aws-cdk/service-spec-types';
import { AllFieldsGiven } from './diff-helpers';

/**
* Options for the resourceBuilder API
*/
export interface ResourceBuilderOptions {
description?: string;
region?: string;
primaryIdentifier?: string[];
}

/**
* Adds resources and types to a spec database
*/
export class SpecBuilder {
constructor(public readonly db: SpecDatabase) {}

public resourceBuilder(typeName: string, options: { description?: string; region?: string } = {}) {
public resourceBuilder(typeName: string, options: ResourceBuilderOptions = {}) {
const existing = this.db.lookup('resource', 'cloudFormationType', 'equals', typeName);

if (existing.length > 0) {
const resource = existing.only();
if (!resource.documentation && options.description) {
resource.documentation = options.description;
}
if (!resource.primaryIdentifier) {
resource.primaryIdentifier = options.primaryIdentifier;
}

return new ResourceBuilder(this.db, resource);
}

const resource = this.db.allocate('resource', {
cloudFormationType: typeName,
documentation: options.description,
name: last(typeName.split('::')),
primaryIdentifier: options.primaryIdentifier,
attributes: {},
properties: {},
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { emptyDatabase } from '@aws-cdk/service-spec-types';
import { importCloudFormationRegistryResource } from '../src/import-cloudformation-registry';
import { ProblemReport } from '../src/report';

let db: ReturnType<typeof emptyDatabase>;
let report: ProblemReport;
beforeEach(() => {
db = emptyDatabase();
report = new ProblemReport();
});

test('include primaryIdentifier in database', () => {
importCloudFormationRegistryResource({
db,
report,
resource: {
typeName: 'AWS::Some::Type',
description: 'resource with PrimaryIdentifier',
properties: {
id: {
type: 'string',
},
secondId: {
type: 'string',
},
notId: {
type: 'string',
},
},
primaryIdentifier: ['/properties/id', '/properties/secondId'],
},
});

// eslint-disable-next-line prettier/prettier
const primaryIdentifier = db.lookup('resource', 'cloudFormationType', 'equals', 'AWS::Some::Type')[0]?.primaryIdentifier;
expect(primaryIdentifier).toEqual(['id', 'secondId']);
});
1 change: 1 addition & 0 deletions packages/@aws-cdk/service-spec-types/src/types/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export interface UpdatedResource {
readonly tagInformation?: ScalarDiff<Resource['tagInformation']>;
readonly scrutinizable?: ScalarDiff<Resource['scrutinizable']>;
readonly typeDefinitionDiff?: MapDiff<TypeDefinition, UpdatedTypeDefinition>;
readonly primaryIdentifier?: ListDiff<string, void>;
}

export interface UpdatedProperty {
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/service-spec-types/src/types/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface Resource extends Entity {
*/
cloudFormationTransform?: string;
documentation?: string;
primaryIdentifier?: string[];
readonly properties: ResourceProperties;
readonly attributes: Record<string, Attribute>;
readonly validations?: unknown;
Expand Down

0 comments on commit 8cb9f96

Please sign in to comment.