Skip to content

Commit

Permalink
feat!: generate all api resources and resource definition which is re…
Browse files Browse the repository at this point in the history
…ferenced. (#222)

* logic

* tests pass

* lint

* feedback
  • Loading branch information
xiaozhenliu-gg5 committed Feb 1, 2020
1 parent b42d6db commit 1e00a2d
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 242 deletions.
15 changes: 9 additions & 6 deletions typescript/src/schema/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import * as path from 'path';
import { Naming, Options as namingOptions } from './naming';
import { Proto, MessagesMap } from './proto';
import { ResourceDatabase, ResourceDescriptor } from './resourceDatabase';
import { Options } from 'yargs-parser';

const googleGaxLocation = path.dirname(require.resolve('google-gax'));
const gaxProtosLocation = path.join(googleGaxLocation, '..', '..', 'protos');
Expand Down Expand Up @@ -54,7 +53,9 @@ export class API {
this.publishName =
options.publishName || this.naming.productName.toKebabCase();
// construct resource map
const resourceMap = getResourceDatabase(fileDescriptors);
const [resourceDatabase, resourceDefinitionDatabase] = getResourceDatabase(
fileDescriptors
);
// parse resource map to Proto constructor
this.protos = fileDescriptors
.filter(fd => fd.name)
Expand All @@ -64,7 +65,8 @@ export class API {
fd,
packageName,
options.grpcServiceConfig,
resourceMap
resourceDatabase,
resourceDefinitionDatabase
);
return map;
}, {} as ProtosMap);
Expand Down Expand Up @@ -131,13 +133,14 @@ export class API {

function getResourceDatabase(
fileDescriptors: plugin.google.protobuf.IFileDescriptorProto[]
): ResourceDatabase {
): ResourceDatabase[] {
const resourceDatabase = new ResourceDatabase();
const resourceDefinitionDatabase = new ResourceDatabase();
for (const fd of fileDescriptors.filter(fd => fd)) {
// process file-level options
for (const resource of fd.options?.['.google.api.resourceDefinition'] ??
[]) {
resourceDatabase.registerResource(
resourceDefinitionDatabase.registerResource(
resource as ResourceDescriptor,
`file ${fd.name} resource_definition option`
);
Expand All @@ -158,5 +161,5 @@ function getResourceDatabase(
);
}
}
return resourceDatabase;
return [resourceDatabase, resourceDefinitionDatabase];
}
52 changes: 26 additions & 26 deletions typescript/src/schema/proto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,8 @@ function augmentService(
service: plugin.google.protobuf.IServiceDescriptorProto,
commentsMap: CommentsMap,
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig,
resourceDatabase: ResourceDatabase
resourceDatabase: ResourceDatabase,
resourceDefinitionDatabase: ResourceDatabase
) {
const augmentedService = service as ServiceDescriptorProto;
augmentedService.packageName = packageName;
Expand Down Expand Up @@ -526,55 +527,52 @@ function augmentService(

// Build a list of resources referenced by this service
const uniqueResources: { [name: string]: ResourceDescriptor } = {};
// Copy all resources in resourceDatabase to uniqueResources
const allPatterns = resourceDatabase.patterns;
for (const pattern of Object.keys(allPatterns)) {
const resource = allPatterns[pattern];
uniqueResources[resource.name] = resource;
}

// Copy all resources definination which are referenced into unique resources map.
for (const property of Object.keys(messages)) {
const errorLocation = `service ${service.name} message ${property}`;
// take the option['.google.api.resource'] of the message as resource, add it to resourceDatabase id it's not there.
const descriptorProto = messages[property];
if (
descriptorProto.options &&
descriptorProto.options['.google.api.resource']
) {
const resource = descriptorProto.options['.google.api.resource'];
if (!resourceDatabase.getResourceByType(resource.type)) {
resourceDatabase.registerResource(resource);
const registeredResource = resourceDatabase.getResourceByType(
resource.type
)!;
uniqueResources[registeredResource.name] = registeredResource;
}
}
for (const fieldDescriptor of messages[property].field ?? []) {
// note: ResourceDatabase can accept `undefined` values, so we happily use optional chaining here.
const resourceReference =
fieldDescriptor.options?.['.google.api.resourceReference'];

// 1. If this resource reference has .child_type, figure out if we have any known parent resources.
const parentResources = resourceDatabase.getParentResourcesByChildType(
const parentResources = resourceDefinitionDatabase.getParentResourcesByChildType(
resourceReference?.childType,
errorLocation
);
parentResources.map(
resource => (uniqueResources[resource.name] = resource)
);

// 2. If this resource reference has .type, we should have a known resource with this type.
const resourceByType = resourceDatabase.getResourceByType(
resourceReference?.type,
errorLocation
// 2. If this resource reference has .type, we should have a known resource with this type, check two maps.
let resourceByType = resourceDefinitionDatabase.getResourceByType(
resourceReference?.type
);
resourceByType =
resourceByType ??
resourceDatabase.getResourceByType(
resourceReference?.type,
errorLocation
);
if (!resourceByType || !resourceByType.pattern) continue;
// For multi pattern resources, we look up the type first, and get the [pattern] from resource,
// look up pattern map for all resources.
for (const pattern of resourceByType!.pattern!) {
const resourceByPattern = resourceDatabase.getResourceByPattern(
const resourceByPattern = resourceDefinitionDatabase.getResourceByPattern(
pattern
);
if (!resourceByPattern) continue;
uniqueResources[resourceByPattern.name] = resourceByPattern;
}
}
}
augmentedService.pathTemplates = Object.values(uniqueResources);
augmentedService.pathTemplates = Object.values(uniqueResources).sort();
return augmentedService;
}

Expand All @@ -590,7 +588,8 @@ export class Proto {
fd: plugin.google.protobuf.IFileDescriptorProto,
packageName: string,
grpcServiceConfig: plugin.grpc.service_config.ServiceConfig,
resourceDatabase: ResourceDatabase
resourceDatabase: ResourceDatabase,
resourceDefinitionDatabase: ResourceDatabase
) {
fd.enumType = fd.enumType || [];
fd.messageType = fd.messageType || [];
Expand Down Expand Up @@ -624,7 +623,8 @@ export class Proto {
service,
commentsMap,
grpcServiceConfig,
resourceDatabase
resourceDatabase,
resourceDefinitionDatabase
)
)
.reduce((map, service) => {
Expand Down
9 changes: 5 additions & 4 deletions typescript/src/schema/resourceDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ export interface ResourceDescriptor
}

export class ResourceDatabase {
private patterns: { [pattern: string]: ResourceDescriptor };
private types: { [type: string]: ResourceDescriptor };
patterns: { [pattern: string]: ResourceDescriptor };
types: { [type: string]: ResourceDescriptor };

constructor() {
this.patterns = {};
Expand Down Expand Up @@ -92,8 +92,9 @@ export class ResourceDatabase {
};
this.patterns[pattern] = resourceDescriptor;
resourceDescriptor = this.getResourceDescriptor(name, params, resource);
if (this.types[resource.type]) continue;
this.types[resource.type] = resourceDescriptor;
if (!this.types[resource.type]) {
this.types[resource.type] = resourceDescriptor;
}
}
}
}
Expand Down

0 comments on commit 1e00a2d

Please sign in to comment.