Why does protobuf miss some params when equals to 0 in python? - python-3.x

I expect that there is no missing value when i serialize and parse, but protoc version 3.9.2 have a problem.
the protofile is show below:
syntax = "proto3";
package example;
message person {
int32 id = 1;
string name = 2;
}
message all_person {
repeated person Per = 1;
}
when i set id=0, name='hello' , i expect to show the "id": 0,
but after SerializeToString and parseToString, it returns
{
"Per": [
{
"name": "hello"
}
]
}
but if i set id=1,name='hello', it returns
{
"Per": [
{
"id": 1,
"name": "hello"
}
]
}

Zero is the default value for numerics (similarly, strings default to empty, booleans to false). See here for more details.
For efficiency, Protobuf relies on these default value. In our system (using FastRTPS and Protobuf for pub/sub), default values are not transmitted across the wire. Based on what you're seeing, it doesn't worry about them for serialisation either.
However, this is only the default behaviour and may be changeable. For example, if you're using MessageToJson, you can simply set an optional parameter including_default_value_fields to True, stating you want the defaults output as well:
jsonStr = MessageToJson(myMsg, True)

Related

Terraform: How to Deal with Optional Input Variable

So I came across this general problem and didn't find an answer yet.
Problem: The input value can have optional variables, like the case below, group_memberships is an optional input, at the moment I make it an empty string input for this to work.
But if I comment it out like shown below and run it, I would get the error:
The given key does not identify an element in this collection value.
Basically it's complaining that I don't have list_of_users.test_user.group_memberships.Is there a way to tell terraform if the input is not declared, just ignore it? I know I can leave it the way it is but user can potentially have many optional values, and making lots of empty input doesn't really make sense.
Thanks! First post question, sorry about poor layout for the code : )
in my .tfvars file:
list_of_users = {
regular_user = {
email = "pdv#abc.com",
group_memberships = "regular_group"
},
test_user = {
email = "test#abc.com",
// group_memberships = "" <------ Currently can work if not comment out, looking for solution that I can remove those reduent empty declariation
},
admin_user = {
email = "admin#abc.com",
group_memberships = "admin_group"
}
}
in .tf file:
variable "list_of_users" {}
resource "user_api_from_provider" "user_generate" {
for_each = var.list_of_users
email = each.value["email"]
group_memberships = each.value["group_memberships"] !=""? [user_api_from_provider.group_generate[each.value["group_memberships"]].id] : null
}
There is support for this as a Terraform "experiment" (it's implemented, but could change or be removed in future versions). You have to declare in your module that you're using the experiment:
terraform {
# Optional attributes and the defaults function are
# both experimental, so we must opt in to the experiment.
experiments = [module_variable_optional_attrs]
}
And then you would use it in your case like this:
variable "list_of_users" {
type = map(object({
email = string
group_memberships = optional(string)
}))
}
Now, if group_membership isn't defined for a given user, that field will have the value of null, so you can now do:
resource "user_api_from_provider" "user_generate" {
...
group_memberships = each.value.group_memberships != null ? [user_api_from_provider.group_generate[each.value["group_memberships"]].id] : null
}
Alternatively, if you don't want to use the experiment, you should be able to do this (untested):
resource "user_api_from_provider" "user_generate" {
...
group_memberships = contains(each.value, "group_memberships") ? [user_api_from_provider.group_generate[each.value["group_memberships"]].id] : null
}
As of Terraform v1.3 the Optional Object Type Attributes feature is official, which means it is no longer an experiment and the syntax is considered stable.
As mentioned in previous comments, you can now do something like:
variable "list_of_users" {
type = map(object({
email = string
group_memberships = optional(string, "")
}))
}
In the above example, using the default value ("") allows the Terraform code in the project/module to function as if there is always a value even if it is omitted from the input variables.

TypeScript / JavaScript gRPC google.protobuf.Struct cannot be read

I have a TypeScript server trying to read a JSON object using a Struct but it seems to be partially working only for objects containing a "fields" key which then expects an object as value. Nonetheless, a Struct should work with any JSON object.
Using BloomRPC I am trying the following message:
{
"payload": {
"fields": {
"Hello": {
"whatever": 0
}
}
}
}
The server reads:
{ fields: { Hello: {} } }
If I send:
{
"payload": {
"anotherfield": {
"HelloWorld": {
"whatever": 0
}
}
}
}
I get an empty object on the server.
The simplified protobuf file looks like this:
syntax = "proto3";
import "google/protobuf/struct.proto";
// The service definition.
service TestTicketService {
rpc UpdateTicket (UpdateTicketRequest) returns (UpdateTicketResponse);
}
// The request message containing the required ticket information.
message UpdateTicketRequest {
string ticketId = 1;
google.protobuf.Struct payload = 2;
}
// The response message containing any potential error message
message UpdateTicketResponse {
string error = 1;
}
Any idea why google/protobuf/struct.proto doesn't work as expected?
What really confused me is that I was trying to pass normal JSON objects and expecting to read them. The whole point is that from the client side, the JSON object needs to be encoded in a very specific way.
For example:
"payload": {
"fields": {
"name": {
"stringValue": "joe"
},
"age": {
"numberValue": 28
}
}
}
You can figure out the format of the message by looking at the Struct proto file here: https://googleapis.dev/nodejs/asset/latest/v1_doc_google_protobuf_doc_struct.js.html
The idea of a struct is that you can store arbitrary data - but only simple types: null, number, string, bool, array and object.
This maps perfectly to JSON, and this is not by accident.
The google.protobuf.Struct message has a special JSON representation:
The JSON representation for Struct is JSON object.
So you can parse any JSON string into a protobuf Struct, and when serializing to JSON again, you also get the same JSON string again.
It is important to note that the in-memory representation of the parsed Struct is not equal to a JSON object. Protobuf does not have dynamic fields and has to represent JSON data in a more complicated manner. That is why struct.proto defines some other types.
When you want to create a Struct in JavaScript, it is probably the easiest way to just create the JSON object you want:
var jsonObject = {foo: "bar"};
var jsonString = JSON.stringify(jsonObject);
Now you can parse you Struct from this jsonObject or jsonString and put set resulting Struct as a field value in another protobuf message.
Since you are already using TypeScript, it might be worth checking out one of the alternative TypeScript implementations for protobuf.
I am the author of protobuf-ts. Creating a Struct is pretty straight-forward:
let struct = Struct.fromJson({foo: "bar"});
First, install #types/google-protobuf and:
let rqm = new UpdateTicketRequest();
rqm.setTicketId("1");
rqm.setPayload(Struct.fromJavaScript({
Hello:{
whatever: 0,
}
});
//and call the api....
UpdateTicket(rqm);

Proper way to parse environment variables

I am using node-config in basically all my projects and most of the time I come across the problem of parsing booleans and numbers which are set as environment variables.
E.g.
default.js
module.exports = {
myNumber = 10,
myBool = true
}
custom-environment-variables.js
module.exports = {
myNumber = "MY_NUMBER",
myBool = "MY_BOOL"
}
Now, the obvious problem is that if I override the default values with custom values set as environment variables they will be a string value instead of a number or boolean value. So now, to make sure in my code that the types are correct. I always have to do type conversion and for booleans use a proper library e.g. yn. The problem is I have to do this conversion every time I use config.get() for example +config.get("myNumber") or yn(config.get("myBool")).
Is there a better and more elegant way to do this?
One solution I see would be to add a type property to an environment variable as it is done here with format. This would allow to do something like this...
custom-environment-variables.js
module.exports = {
myNumber = {
name: "MY_NUMBER",
type: "number"
},
myBool = {
name: "MY_BOOL",
type: "boolean"
}
}
node-config would handle the type conversions and there would be no need to do it all the time in the code when getting it. Of course there would be the requirement to implement a proper parser for booleans but those already exist and could be used here.
By default, environment variables will be parsed as string.
In node-config, we could override this behaviour with __format as shown below.
We don't need any additional libraries. Normal json datatypes like boolean, number, nested json etc., should work well.
Taking an easy to relate example.
config/default.json
{
"service": {
"autostart": false
}
}
custom-environment-variables.json
{
"service": {
"autostart": {
"__name": "AUTOSTART",
"__format": "json"
}
}
}
Now we can pass environment variables when we like to override and no type conversation should be needed for basic types.
This feature is now supported in node-config v3.3.2, see changelog
I use this method:
const toBoolean = (dataStr) => {
return !!(dataStr?.toLowerCase?.() === 'true' || dataStr === true);
};
You can add cases if you want 0 to resolve to true as well:
const toBoolean = (dataStr) => {
return !!(dataStr?.toLowerCase?.() === 'true' || dataStr === true || Number.parseInt(dataStr, 10) === 0);
};

Terraform module with repeatable variable

Several resources, e.g. aws_dynamodb_table have repeatable variables. In the case of the aws_dynamodb_table resource, attribute is repeatable which allows you to specify multiple attributes using either of the following syntax
attribute {
name = "UserId"
type = "S"
}
attribute {
name = "GameTitle"
type = "S"
}
attribute {
name = "TopScore"
type = "N"
}
or
attribute = [{
name = "UserId"
type = "S"
}, {
name = "GameTitle"
type = "S"
}, {
name = "TopScore"
type = "N"
}]
I like this interface and want to provide the same flexibility in my modules but I can't seem to find any documentation on how to do it. Is this possible for modules or is it only the built-in resources that can do this.
It looks like that either allows you to provide attribute multiple times as separate maps (which are then merged) or as a list.
You're going to want to take a look at the documentation related to Input Variable Configuration
In particular, you will want to look at the section titled Variable Merging.
I believe you could do something like this for similar behavior (from the docs above, give them a read :P)
foo {
quux="bar"
}
foo {
bar="baz"
}
This would mean foo returns:
{
quux = "bar"
bar = "baz"
}
Hope that helps!

Need to get the values of the objects (JSON) which have been created dynamically

How to get the top object value in PentahoDI? I have got the other elements like Category, Subcategory, section from the following example of Json file. However, I need to capture the first root object which is x#chapter#e50de0196d77495d9b50fc05567b4a4b and x#e50de0196d77495d9b50fc05567b4a4b
{
"x#chapter#e50de0196d77495d9b50fc05567b4a4b": {
"Category": "chapter",
"SubCategory": [
"x#4eb9072cf36f4d6fa1e98717e6bb54f7",
"x#d85849fbde324690b6067f3b18c4258d",
"x#3edff1a1864f41fe8b212df2bc96bf13"
],
"Section": {
"display_name": "Week 1 Section"
}
},
"x#e50de0196d77495d9b50fc05567b4a4b": {
"category": "course",
"Subcategory": [
"x#e50de0196d77495d9b50fc05567b4a4b"
],
"Section": {
"advanced_modules": [
"google-document"
],
}
}
}
In the Fields tab of the Json Input step I have given the Names and Paths as: Category --> $..Category, Subcategory --> $..Subcategory, Section --> $..Section.
However, I am unable to get the root element as it is crucial information for us to work on it. ex (x#chapter#e50de0196d77495d9b50fc05567b4a4b and x#e50de0196d77495d9b50fc05567b4a4b)
I have used the following code to get the values of the dynamic objects but it didnt work. The following is the code I used it.
var obj = JSON.parse (JBlock) //Jblock is the one which holds the entire string.
var keys = Object.name( obj);
JSONPath is not able to get the keys of a JSON structure. This is one of my main issues with JSONPath, and I wish Pentaho had included other JSON parsing engines.
This JavaScript to be used in Modified Java Script Value works for me. Add a value in the fields editor like this:
And then a script like this:
var obj = JSON.parse(JBlock);
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
    var row = createRowCopy(getOutputRowMeta().size());
    var idx = getInputRowMeta().size();
row[idx++] = keys[i];
putRow(row);
}
trans_Status = SKIP_TRANSFORMATION;

Resources