From 787f6637287d662a57396d8b531f58a81939c3e7 Mon Sep 17 00:00:00 2001 From: Timo Stamm Date: Wed, 17 Aug 2022 14:04:51 +0200 Subject: [PATCH] Clarify mergePartial() behavior --- MANUAL.md | 24 ++++++++++++++++++- packages/runtime/src/message-type-contract.ts | 19 +++++++++++++++ .../runtime/src/reflection-merge-partial.ts | 24 ++++++++++++------- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/MANUAL.md b/MANUAL.md index 5a9b0428..99cb80a5 100644 --- a/MANUAL.md +++ b/MANUAL.md @@ -471,7 +471,27 @@ The `IMessageType` interface provides the following methods: - `mergePartial(target: T, source: PartialMessage): void` - Copy partial data into the target message. + Copy partial data into the target message. + + If a singular scalar or enum field is present in the source, it + replaces the field in the target. + + If a singular message field is present in the source, it is merged + with the target field by calling mergePartial() of the responsible + message type. + + If a repeated field is present in the source, its values replace + all values in the target array, removing extraneous values. + Repeated message fields are copied, not merged. + + If a map field is present in the source, entries are added to the + target map, replacing entries with the same key. Entries that only + exist in the target remain. Entries with message values are copied, + not merged. + + Note that this function differs from protobuf merge semantics, + which appends repeated fields. + - `equals(a: T, b: T): boolean` @@ -481,12 +501,14 @@ The `IMessageType` interface provides the following methods: Accepts `undefined` for convenience, but will return false if one or both arguments are undefined. + - `is(arg: any, depth?: number): arg is T` Is the given value assignable to our message type and contains no excess properties? Learn more about the [Message type guards](#message-type-guards). + - `isAssignable(arg: any, depth?: number): arg is T` Is the given value assignable to our message type, diff --git a/packages/runtime/src/message-type-contract.ts b/packages/runtime/src/message-type-contract.ts index 8a7b5d06..d4590101 100644 --- a/packages/runtime/src/message-type-contract.ts +++ b/packages/runtime/src/message-type-contract.ts @@ -125,6 +125,25 @@ export interface IMessageType extends MessageInfo { /** * Copy partial data into the target message. + * + * If a singular scalar or enum field is present in the source, it + * replaces the field in the target. + * + * If a singular message field is present in the source, it is merged + * with the target field by calling mergePartial() of the responsible + * message type. + * + * If a repeated field is present in the source, its values replace + * all values in the target array, removing extraneous values. + * Repeated message fields are copied, not merged. + * + * If a map field is present in the source, entries are added to the + * target map, replacing entries with the same key. Entries that only + * exist in the target remain. Entries with message values are copied, + * not merged. + * + * Note that this function differs from protobuf merge semantics, + * which appends repeated fields. */ mergePartial(target: T, source: PartialMessage): void; diff --git a/packages/runtime/src/reflection-merge-partial.ts b/packages/runtime/src/reflection-merge-partial.ts index e03d1475..00ff1d5a 100644 --- a/packages/runtime/src/reflection-merge-partial.ts +++ b/packages/runtime/src/reflection-merge-partial.ts @@ -6,16 +6,24 @@ import type {UnknownMessage, UnknownOneofGroup} from "./unknown-types"; /** * Copy partial data into the target message. * - * Replaces fields in the target with the fields from the - * (partial) source. + * If a singular scalar or enum field is present in the source, it + * replaces the field in the target. * - * Omitted fields are not replaced. - * Copies all values. - * A default value in the source will replace a value in the target. + * If a singular message field is present in the source, it is merged + * with the target field by calling mergePartial() of the responsible + * message type. * - * Message fields are recursively merged (by calling `mergePartial()` - * of the responsible message handler). Map and repeated fields - * are simply overwritten, not appended or merged. + * If a repeated field is present in the source, its values replace + * all values in the target array, removing extraneous values. + * Repeated message fields are copied, not merged. + * + * If a map field is present in the source, entries are added to the + * target map, replacing entries with the same key. Entries that only + * exist in the target remain. Entries with message values are copied, + * not merged. + * + * Note that this function differs from protobuf merge semantics, + * which appends repeated fields. */ export function reflectionMergePartial(info: MessageInfo, target: T, source: PartialMessage) {