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: extensions #808

Merged
merged 2 commits into from
Apr 1, 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
7 changes: 6 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ Generated code will be placed in the Gradle build directory.

- With `--ts_proto_opt=useJsonWireFormat=true`, the generated code will reflect the JSON representation of Protobuf messages.

Requires `onlyTypes=true`. Implies `useDate=string` and `stringEnums=true`. This option is to generate types that can be directly used with marshalling/unmarshalling Protobuf messages serialized as JSON.
Requires `onlyTypes=true`. Implies `useDate=string` and `stringEnums=true`. This option is to generate types that can be directly used with marshalling/unmarshalling Protobuf messages serialized as JSON.
You may also want to set `useOptionals=all`, as gRPC gateways are not required to send default value for scalar values.

- With `--ts_proto_opt=useNumericEnumForJson=true`, the JSON converter (`toJSON`) will encode enum values as int, rather than a string literal.
Expand Down Expand Up @@ -502,6 +502,11 @@ Generated code will be placed in the Gradle build directory.

by default this is enabled which would generate a type of `Box_Element_Image_Alignment`. By disabling this option the type that is generated would be `BoxElementImageAlignment`.

- With `--ts_proto_opt=outputExtensions=true`, the generated code will include proto2 extensions

Extension encode/decode methods are compliant with the `outputEncodeMethods` option, and if `unknownFields=true`,
the `setExtension` and `getExtension` methods will be created for extendable messages, also compliant with `outputEncodeMethods` (setExtension = encode, getExtension = decode).

### NestJS Support

We have a great way of working together with [nestjs](https://docs.nestjs.com/microservices/grpc). `ts-proto` generates `interfaces` and `decorators` for you controller, client. For more information see the [nestjs readme](NESTJS.markdown).
Expand Down
103 changes: 103 additions & 0 deletions integration/extensions/extensions-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Extendable, Nested, packed, repeated, bytes, string, long, fixed, enumField, group, Enum } from './test';
import * as Long from 'long';

describe('extensions-test', () => {
it('works with namespaced extensions', () => {
const test: Extendable = {
field: 'hello'
};

const extensionData = [
{
field: 'a'
},
{
field: 'b'
}
];

Extendable.setExtension(test, Nested.message, extensionData);

const encoded = Extendable.encode(test).finish();
const result = Extendable.decode(encoded);

expect(result).toEqual(test);

const extension = Extendable.getExtension(result, Nested.message);

expect(extension).toEqual(extensionData);

const unsetExtension = Extendable.getExtension(result, packed);

expect(unsetExtension).toEqual(undefined);
});

it('works with repeated fields', () => {
const test: Extendable = {
field: 'repeated',

_unknownFields: {
[(6 << 3) | 2]: [Buffer.from([1, 1]), Buffer.from([1, 1])],
[(6 << 3) | 0]: [Buffer.from([2]), Buffer.from([3]), Buffer.from([5])]
}
};

const extensionData = [1, 2, 3, 4, 5];

Extendable.setExtension(test, packed, extensionData);

const encoded = Extendable.encode(test).finish();
const result = Extendable.decode(encoded);

expect(result).toEqual(test);

const extension = Extendable.getExtension(result, packed);

expect(extension).toEqual(extensionData);

expect(Extendable.getExtension(result, repeated)).toEqual([1, 1, 2, 3, 5]);

const unsetExtension = Extendable.getExtension(result, Nested.message);

expect(unsetExtension).toEqual(undefined);
});

it('works with various field types', () => {
const test: Extendable = {
field: 'various'
};

const bytesExtensionData = Buffer.from([2, 3, 5, 7, 11]);
const stringExtensionData = "this is a string";
const longExtensionData = new Long(0x89ABCDEF, 0x01234567, false);
const fixedExtensionData = new Long(0x01234567, 0x89ABCDEF, true);
const enumExtensionData = Enum.ENUM_ONE;
const groupExtensionData = {
name: 'this is',
value: 'a group'
};

Extendable.setExtension(test, bytes, bytesExtensionData);
Extendable.setExtension(test, string, stringExtensionData);
Extendable.setExtension(test, long, longExtensionData);
Extendable.setExtension(test, fixed, fixedExtensionData);
Extendable.setExtension(test, enumField, enumExtensionData);
Extendable.setExtension(test, group, groupExtensionData);

const encoded = Extendable.encode(test).finish();
const result = Extendable.decode(encoded);

expect(result).toEqual(test);

expect( Extendable.getExtension(result, bytes) ).toEqual(bytesExtensionData);
expect( Extendable.getExtension(result, string) ).toEqual(stringExtensionData);
expect( Extendable.getExtension(result, long) ).toEqual(longExtensionData);
expect( Extendable.getExtension(result, fixed) ).toEqual(fixedExtensionData);
expect( Extendable.getExtension(result, enumField) ).toEqual(enumExtensionData);
expect( Extendable.getExtension(result, group) ).toEqual(groupExtensionData);

const unsetExtension = Extendable.getExtension(result, Nested.message);

expect(unsetExtension).toEqual(undefined);
});
});
1 change: 1 addition & 0 deletions integration/extensions/parameters.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
outputExtensions=true,forceLong=long,unknownFields=true,initializeFieldsAsUndefined=false,useOptionals=all
Binary file added integration/extensions/test.bin
Binary file not shown.
35 changes: 35 additions & 0 deletions integration/extensions/test.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
syntax = "proto2";

message Extendable{
required string field = 1;

extensions 4 to max;
}

message Nested{
required string field = 1;

extend Extendable{
repeated Nested message = 4;
}
}

enum Enum{
ENUM_UNRECOGNIZED = 0;
ENUM_ONE = 1;
ENUM_TWO = 2;
}

extend Extendable{
repeated int32 packed = 5 [packed = true];
repeated int32 repeated = 6;
optional bytes bytes = 7;
optional string string = 8;
optional int64 long = 9;
optional fixed64 fixed = 10;
optional Enum enum_field = 11;
optional group Group = 12 {
optional string name = 1;
optional string value = 2;
}
}
Loading