Skip to content

V2: Introduce DescMessage.field#839

Merged
timostamm merged 1 commit intov2from
tstamm/DescMessage.field
May 13, 2024
Merged

V2: Introduce DescMessage.field#839
timostamm merged 1 commit intov2from
tstamm/DescMessage.field

Conversation

@timostamm
Copy link
Member

In some situations, it's useful to be able to refer to a field by name.

DescMessage provides all fields in the property fields: DescField[] - that's convenient to loop through all fields, but it's awkward to pick a field by name.

This PR adds another property to DescMessage:

/**
 * All fields of this message by their "localName".
 */
readonly field: Record<string, DescField>;

In generated code, the property is a type-safe record. You get autocomplete for field names, and a typo is a compile-time error:

import { UserDesc } from "./gen/example_pb.js";

UserDesc.field.firstName; // DescField
UserDesc.field.firstNam; // type error

This PR also changes the signatures of isFieldSet and clearField to make use of this new feature. Instead of having to pass in the message descriptor, the message, and the field name, both functions only require two arguments now: The message, and the field:

import { create, clearField } from "@bufbuild/protobuf";
import { UserDesc } from "./gen/example_pb.js";

const user = create(UserDesc);
clearField(user, UserDesc.field.firstName);

const oneof = findOneof(proto, allOneofs);
const field = newField(proto, message, reg, oneof, mapEntries);
message.fields.push(field);
message.field[field.localName] = field;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're eagerly populating the record - it's quite simple and cheap.

export function getPackageComments(desc: DescFile): DescComments {
return findComments(desc.proto.sourceCodeInfo, [
FieldNumber.FileDescriptorProto_Package,
FileDescriptorProtoDesc.field.package.number,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a nice practical example of where this feature can be useful. I imagine it will also be useful to construct FieldMasks.

Comment on lines +37 to +41
field: DescField,
): boolean {
const field = messageDesc.fields.find((f) => f.localName === fieldName);
if (field) {
return unsafeIsSet(message, field);
}
return false;
return (
field.parent.typeName == message.$typeName && unsafeIsSet(message, field)
);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, a foreign field is never set, and clearing a foreign field is a no-op.

@timostamm timostamm requested a review from srikrsna-buf May 13, 2024 09:12
@timostamm timostamm changed the title Introduce DescMessage.field V2: Introduce DescMessage.field May 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants