Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: generate all api resources and resource definition which is referenced. #222

Merged
merged 5 commits into from
Feb 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 };
xiaozhenliu-gg5 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading