Skip to content

Customer wrapper for Struct #929

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
16 changes: 9 additions & 7 deletions src/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ function genValuePartial_fromObject(gen, field, fieldIndex, prop) {
("break");
} gen
("}");
} else gen
("if(typeof d%s!==\"object\")", prop)
("throw TypeError(%j)", field.fullName + ": object expected")
} else {
gen
// ("if(typeof d%s!==\"object\")", prop)
// ("throw TypeError(%j)", field.fullName + ": object expected")
("m%s=types[%i].fromObject(d%s)", prop, fieldIndex, prop);
}
} else {
var isUnsigned = false;
switch (field.type) {
Expand Down Expand Up @@ -133,10 +135,10 @@ converter.fromObject = function fromObject(mtype) {
// Non-repeated fields
} else {
if (!(field.resolvedType instanceof Enum)) gen // no need to test for null/undefined if an enum (uses switch)
("if(d%s!=null){", prop); // !== undefined && !== null
genValuePartial_fromObject(gen, field, /* not sorted */ i, prop);
if (!(field.resolvedType instanceof Enum)) gen
("}");
// ("if(d%s!=null){", prop); // !== undefined && !== null
genValuePartial_fromObject(gen, field, /* not sorted */ i, prop);
// if (!(field.resolvedType instanceof Enum)) gen
// ("}");
}
} return gen
("return m");
Expand Down
90 changes: 90 additions & 0 deletions src/wrappers.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,93 @@ wrappers[".google.protobuf.Any"] = {
return this.toObject(message, options);
}
};

// Custom wrapper for ListValue
wrappers[".google.protobuf.ListValue"] = {
fromObject: function(object) {
var Value = this.lookup("google.protobuf.Value");
return this.create({values: object.map(Value.fromObject)});
},

toObject: function(message /*, options */) {
var Value = this.lookup("google.protobuf.Value");
return message.values.map(Value.toObject);
}
};

// Custom wrapper for Value
wrappers[".google.protobuf.Value"] = {
// given a plain javascript scalar or object, return a protobuf Value
fromObject: function(object) {
var Struct = this.lookup("google.protobuf.Struct");
var NullValue = this.lookup("google.protobuf.NullValue");
var ListValue = this.lookup("google.protobuf.ListValue");

var valueDef;
if (object === null) {
valueDef = {nullValue: NullValue.values.NULL_VALUE};
} else if (typeof object === "number") {
valueDef = {numberValue: object};
} else if (typeof object === "string") {
valueDef = {stringValue: object};
} else if (typeof object === "boolean") {
valueDef = {boolValue: object};
} else if (Array.isArray(object)) {
valueDef = {listValue: ListValue.fromObject(object)};
} else if (typeof object === "object") {
valueDef = {structValue: Struct.fromObject(object)};
} else {
return valueDef = {nullValue: 0};
}
return this.create(valueDef);
},

toObject: function(message, options) {
var Struct = this.lookup("google.protobuf.Struct");
var ListValue = this.lookup("google.protobuf.ListValue");

var object;
if (message.kind === "nullValue") {
object = null;
} else if (message.kind === "numberValue") {
object = message.numberValue;
} else if (message.kind === "stringValue") {
object = message.stringValue;
} else if (message.kind === "boolValue") {
object = message.boolValue;
} else if (message.kind === "structValue") {
object = Struct.toObject(message.structValue, options);
} else if (message.kind === "listValue") {
object = ListValue.toObject(message.listValue, options);
}

return object;
}
};

// Custom wrapper for Struct
wrappers[".google.protobuf.Struct"] = {

// given a plain javascript object, return a protobuf Struct object
fromObject: function(object) {
var Value = this.lookup("google.protobuf.Value");
var structDef = {fields: {}};

Object.keys(object).forEach(function (k) {
structDef.fields[k] = Value.fromObject(object[k]);
});
return this.create(structDef);
},

// given a protobuf Struct object, return a plain JS object
toObject: function(message, options) {
var Value = this.lookup("google.protobuf.Value");
var object = {};
var fields = message.fields;

Object.keys(fields).forEach(function (k) {
object[k] = Value.toObject(fields[k], options);
});
return object;
}
};
67 changes: 67 additions & 0 deletions tests/comp_google_protobuf_struct.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
var tape = require("tape");

var protobuf = require("..");

var root = protobuf.Root.fromJSON({
nested: {
Foo: {
fields: {
foo: {
id: 1,
type: "google.protobuf.Struct"
}
}
}
}
})
.addJSON(protobuf.common["google/protobuf/struct.proto"].nested)
.resolveAll();

var Struct = root.lookupType("protobuf.Struct"),
Value = root.lookupType("protobuf.Value"),
Foo = root.lookupType(".Foo");

tape.test("google.protobuf.Struct", function(test) {
var foo = Foo.fromObject({foo: {
a: null,
b: 1,
c: 'd',
e: false,
f: {g: 2},
h: [null, 3, 'i', true]
}});

test.ok(foo.foo instanceof Struct.ctor, "foo should be Struct");
Object.keys(foo.foo.fields).forEach(function(k) {
test.ok(foo.foo.fields[k] instanceof Value.ctor, "foo." + k + " should be Value");
});
test.same(foo, {foo: {
fields: {
a: {nullValue: 0 },
b: {numberValue: 1},
c: {stringValue: "d"},
e: {boolValue: false},
f: {structValue: {fields: {
g: {numberValue: 2}
}}},
h: {listValue: {values: [
{nullValue: 0},
{numberValue: 3},
{stringValue: "i"},
{boolValue: true}
]}}
}
}});

var obj = Foo.toObject(foo);
test.same(obj, {foo: {
a: null,
b: 1,
c: 'd',
e: false,
f: {g: 2},
h: [null, 3, 'i', true]
}});

test.end();
});
79 changes: 79 additions & 0 deletions tests/comp_google_protobuf_value.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
var tape = require("tape");

var protobuf = require("..");

var root = protobuf.Root.fromJSON({
nested: {
Foo: {
fields: {
foo: {
id: 1,
type: "google.protobuf.Value"
}
}
}
}
})
.addJSON(protobuf.common["google/protobuf/struct.proto"].nested)
.resolveAll();

var Value = root.lookupType("protobuf.Value"),
Foo = root.lookupType(".Foo");

tape.test.only("google.protobuf.Value", function(test) {
// null
var foo = Foo.fromObject({foo: null});
test.ok(foo.foo instanceof Value.ctor, "foo should be Value");
test.same(foo.foo.kind, "nullValue");
test.same(foo.foo.nullValue, 0);

var obj = Foo.toObject(foo);
test.same(obj.foo, null);

// number
foo = Foo.fromObject({foo: 1});
test.ok(foo.foo instanceof Value.ctor, "foo should be Value");
test.same(foo.foo.kind, "numberValue");
test.same(foo.foo.numberValue, 1);

obj = Foo.toObject(foo);
test.same(obj.foo, 1);

// string
foo = Foo.fromObject({foo: "a"});
test.ok(foo.foo instanceof Value.ctor, "foo should be Value");
test.same(foo.foo.kind, "stringValue");
test.same(foo.foo.stringValue, "a");

obj = Foo.toObject(foo);
test.same(obj.foo, "a");

// boolean
foo = Foo.fromObject({foo: false});
test.ok(foo.foo instanceof Value.ctor, "foo should be Value");
test.same(foo.foo.kind, "boolValue");
test.same(foo.foo.boolValue, false);

obj = Foo.toObject(foo);
test.same(obj.foo, false);

// object
foo = Foo.fromObject({foo: {a: 1}});
test.ok(foo.foo instanceof Value.ctor, "foo should be Value");
test.same(foo.foo.kind, "structValue");
test.same(foo.foo.structValue, {fields: {a: {numberValue: 1}}});

obj = Foo.toObject(foo);
test.same(obj.foo, {a: 1});

// list
foo = Foo.fromObject({foo: [null, 1, "a", true]});
test.ok(foo.foo instanceof Value.ctor, "foo should be Value");
test.same(foo.foo.kind, "listValue");
test.same(foo.foo.listValue, {values: [{nullValue: 0}, {numberValue: 1}, {stringValue: "a"}, {boolValue: true}]});

obj = Foo.toObject(foo);
test.same(obj.foo, [null, 1, "a", true]);

test.end();
});