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: add support for Struct in NestJS #762

Merged
merged 9 commits into from
Jan 31, 2023
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
2 changes: 0 additions & 2 deletions integration/fieldmask/google/protobuf/field_mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,7 @@ export const FieldMask = {

wrap(paths: string[]): FieldMask {
const result = createBaseFieldMask();

result.paths = paths;

return result;
},

Expand Down
28 changes: 15 additions & 13 deletions integration/grpc-js/google/protobuf/struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,11 @@ export const Struct = {

unwrap(message: Struct): { [key: string]: any } {
const object: { [key: string]: any } = {};
Object.keys(message.fields).forEach((key) => {
object[key] = message.fields[key];
});
if (message.fields) {
Object.keys(message.fields).forEach((key) => {
object[key] = message.fields[key];
});
}
return object;
},
};
Expand Down Expand Up @@ -360,7 +362,6 @@ export const Value = {

wrap(value: any): Value {
const result = createBaseValue();

if (value === null) {
result.nullValue = NullValue.NULL_VALUE;
} else if (typeof value === "boolean") {
Expand All @@ -376,19 +377,18 @@ export const Value = {
} else if (typeof value !== "undefined") {
throw new Error("Unsupported any value type: " + typeof value);
}

return result;
},

unwrap(message: Value): string | number | boolean | Object | null | Array<any> | undefined {
if (message?.stringValue !== undefined) {
unwrap(message: any): string | number | boolean | Object | null | Array<any> | undefined {
if (message.stringValue !== undefined) {
return message.stringValue;
} else if (message?.numberValue !== undefined) {
return message.numberValue;
} else if (message?.boolValue !== undefined) {
return message.boolValue;
} else if (message?.structValue !== undefined) {
return message.structValue;
return message.structValue as any;
} else if (message?.listValue !== undefined) {
return message.listValue;
} else if (message?.nullValue !== undefined) {
Expand Down Expand Up @@ -452,16 +452,18 @@ export const ListValue = {
return message;
},

wrap(value: Array<any> | undefined): ListValue {
wrap(array: Array<any> | undefined): ListValue {
const result = createBaseListValue();

result.values = value ?? [];

result.values = array ?? [];
return result;
},

unwrap(message: ListValue): Array<any> {
return message.values;
if (message?.hasOwnProperty("values") && Array.isArray(message.values)) {
return message.values;
} else {
return message as any;
}
},
};

Expand Down
172 changes: 172 additions & 0 deletions integration/nestjs-simple/google/protobuf/struct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* eslint-disable */
import { wrappers } from "protobufjs";

export const protobufPackage = "google.protobuf";

/**
* `NullValue` is a singleton enumeration to represent the null value for the
* `Value` type union.
*
* The JSON representation for `NullValue` is JSON `null`.
*/
export enum NullValue {
/** NULL_VALUE - Null value. */
NULL_VALUE = 0,
UNRECOGNIZED = -1,
}

/**
* `Struct` represents a structured data value, consisting of fields
* which map to dynamically typed values. In some languages, `Struct`
* might be supported by a native representation. For example, in
* scripting languages like JS a struct is represented as an
* object. The details of that representation are described together
* with the proto support for the language.
*
* The JSON representation for `Struct` is JSON object.
*/
export interface Struct {
/** Unordered map of dynamically typed values. */
fields: { [key: string]: any | undefined };
}

export interface Struct_FieldsEntry {
key: string;
value: any | undefined;
}

/**
* `Value` represents a dynamically typed value which can be either
* null, a number, a string, a boolean, a recursive struct value, or a
* list of values. A producer of value is expected to set one of these
* variants. Absence of any variant indicates an error.
*
* The JSON representation for `Value` is JSON value.
*/
export interface Value {
/** Represents a null value. */
nullValue?:
| NullValue
| undefined;
/** Represents a double value. */
numberValue?:
| number
| undefined;
/** Represents a string value. */
stringValue?:
| string
| undefined;
/** Represents a boolean value. */
boolValue?:
| boolean
| undefined;
/** Represents a structured value. */
structValue?:
| { [key: string]: any }
| undefined;
/** Represents a repeated `Value`. */
listValue?: Array<any> | undefined;
}

/**
* `ListValue` is a wrapper around a repeated field of values.
*
* The JSON representation for `ListValue` is JSON array.
*/
export interface ListValue {
/** Repeated field of dynamically typed values. */
values: any[];
}

export const GOOGLE_PROTOBUF_PACKAGE_NAME = "google.protobuf";

function createBaseStruct(): Struct {
return { fields: {} };
}

export const Struct = {
wrap(object: { [key: string]: any } | undefined): Struct {
const struct = createBaseStruct();
if (object !== undefined) {
Object.keys(object).forEach((key) => {
struct.fields[key] = Value.wrap(object[key]);
});
}
return struct;
},

unwrap(message: Struct): { [key: string]: any } {
const object: { [key: string]: any } = {};
if (message.fields) {
Object.keys(message.fields).forEach((key) => {
object[key] = Value.unwrap(message.fields[key]);
});
}
return object;
},
};

function createBaseValue(): Value {
return {};
}

export const Value = {
wrap(value: any): Value {
const result = {} as any;
if (value === null) {
result.nullValue = NullValue.NULL_VALUE;
} else if (typeof value === "boolean") {
result.boolValue = value;
} else if (typeof value === "number") {
result.numberValue = value;
} else if (typeof value === "string") {
result.stringValue = value;
} else if (Array.isArray(value)) {
result.listValue = ListValue.wrap(value);
} else if (typeof value === "object") {
result.structValue = Struct.wrap(value);
} else if (typeof value !== "undefined") {
throw new Error("Unsupported any value type: " + typeof value);
}
return result;
},

unwrap(message: any): string | number | boolean | Object | null | Array<any> | undefined {
if (message?.hasOwnProperty("stringValue") && message.stringValue !== undefined) {
return message.stringValue;
} else if (message?.hasOwnProperty("numberValue") && message?.numberValue !== undefined) {
return message.numberValue;
} else if (message?.hasOwnProperty("boolValue") && message?.boolValue !== undefined) {
return message.boolValue;
} else if (message?.hasOwnProperty("structValue") && message?.structValue !== undefined) {
return Struct.unwrap(message.structValue as any);
} else if (message?.hasOwnProperty("listValue") && message?.listValue !== undefined) {
return ListValue.unwrap(message.listValue);
} else if (message?.hasOwnProperty("nullValue") && message?.nullValue !== undefined) {
return null;
}
return undefined;
},
};

function createBaseListValue(): ListValue {
return { values: [] };
}

export const ListValue = {
wrap(array: Array<any> | undefined): ListValue {
const result = createBaseListValue();
result.values = (array ?? []).map(Value.wrap);
return result;
},

unwrap(message: ListValue): Array<any> {
if (message?.hasOwnProperty("values") && Array.isArray(message.values)) {
return message.values.map(Value.unwrap);
} else {
return message as any;
}
},
};

wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any;
Binary file modified integration/nestjs-simple/hero.bin
Binary file not shown.
4 changes: 3 additions & 1 deletion integration/nestjs-simple/hero.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";

import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/struct.proto";

package hero;

Expand All @@ -25,7 +26,8 @@ message VillainById {
message Hero {
int32 id = 1;
string name = 2;
google.protobuf.Timestamp birth_date = 3;
.google.protobuf.Timestamp birth_date = 3;
.google.protobuf.Struct external_data = 4;
}

message Villain {
Expand Down
5 changes: 5 additions & 0 deletions integration/nestjs-simple/hero.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint-disable */
import { GrpcMethod, GrpcStreamMethod } from "@nestjs/microservices";
import { wrappers } from "protobufjs";
import { Observable } from "rxjs";
import { Empty } from "./google/protobuf/empty";
import { Struct } from "./google/protobuf/struct";
import { Timestamp } from "./google/protobuf/timestamp";

export const protobufPackage = "hero";
Expand All @@ -18,6 +20,7 @@ export interface Hero {
id: number;
name: string;
birthDate: Timestamp | undefined;
externalData: { [key: string]: any } | undefined;
}

export interface Villain {
Expand All @@ -27,6 +30,8 @@ export interface Villain {

export const HERO_PACKAGE_NAME = "hero";

wrappers[".google.protobuf.Struct"] = { fromObject: Struct.wrap, toObject: Struct.unwrap } as any;

export interface HeroServiceClient {
addOneHero(request: Hero): Observable<Empty>;

Expand Down
27 changes: 20 additions & 7 deletions integration/nestjs-simple/nestjs-project/hero.controller.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import { Controller } from '@nestjs/common';
import { Observable, Subject } from 'rxjs';
import { Hero, HeroById, HeroServiceController, HeroServiceControllerMethods, Villain, VillainById } from '../hero';
import { Controller } from "@nestjs/common";
import { Observable, Subject } from "rxjs";
import { Hero, HeroById, HeroServiceController, HeroServiceControllerMethods, Villain, VillainById } from "../hero";

@Controller('hero')
@Controller("hero")
@HeroServiceControllerMethods()
export class HeroController implements HeroServiceController {
private readonly heroes: Hero[] = [
{ id: 1, name: 'Stephenh', birthDate: { seconds: 1, nanos: 2 } },
{ id: 2, name: 'Iangregsondev', birthDate: { seconds: 1, nanos: 3 } },
{
id: 1,
name: "Stephenh",
birthDate: { seconds: 1, nanos: 2 },
externalData: { foo: "bar", fizz: 1, nested: { isFailing: false, arr: [1, "foo", ["bar"]] } },
},
{
id: 2,
name: "Iangregsondev",
birthDate: { seconds: 1, nanos: 3 },
externalData: { bar: 10, baz: "foo", isPassing: true },
},
];

private readonly villains: Villain[] = [{ id: 1, name: 'John' }, { id: 2, name: 'Doe' }];
private readonly villains: Villain[] = [
{ id: 1, name: "John" },
{ id: 2, name: "Doe" },
];

addOneHero(request: Hero) {
this.heroes.push(request);
Expand Down
Loading