How to deserialize a json object into rust understandable code using enums? - parsing

I need to deserialize ( and later on serialize ) a piece of data that has this type of a structure :
{
"type": "TypeApplication",
"val": {
"con": {
"type": "TypeConstructor",
"val": [
"Builtin",
"Record"
]
},
"arg": {
"type": "RowCons",
"val": {
"label": "953e3dd6-826e-1985-cb99-fd4ed4da754e",
"type": {
"type": "TypeApplication",
"val": {
"con": {
"type": "TypeConstructor",
"val": [
"Builtin",
"List"
]
},
"arg": {
"type": "Element",
"meta": {
"multiLine": true
}
}
},
"system": {
"label": "nullam-senectus-port - Text",
"isBindable": true,
"defaultValue": [
{
"id": "4a05486f-f24d-45f8-ae13-ab05f824d74d",
"type": "String",
"pluginType": "Basic",
"data": {
"value": "Nullam senectus porttitor in eget. Eget rutrum leo interdum."
},
"children": [],
"text": true
}
],
"isUnlinked": false,
"isDefault": false
}
},
"tail": {
"type": "RowCons",
"val": {
"label": "94f603df-d585-b45a-4252-9ec77cf5b13c",
"type": {
"type": "TypeApplication",
"val": {
"con": {
"type": "TypeConstructor",
"val": [
"Builtin",
"List"
]
},
"arg": {
"type": "Element",
"meta": {
"multiLine": true
}
}
},
"system": {
"label": "best-services - Text",
"isBindable": true,
"defaultValue": [
{
"id": "6265ca45-3f69-4844-97e2-c05bbfb9fee5",
"type": "String",
"pluginType": "Basic",
"data": {
"value": "Best Services"
},
"children": [],
"text": true
}
]
}
},
"tail": {
"type": "RowEmpty"
}
}
}
}
}
}
}
I do not know what this data exactly is, but I know this is trying to represent a function/element that takes in values and defaults for those values as parameters/properties.
I want to deserialize it using serde and consequently serialize it too.
I have so far been able to write something that sort of works but not really :
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(tag = "type", content = "val")]
pub enum WebflowPropDataType {
TypeApplication {
con: Box<WebflowPropDataType>, // Normally Passes the Type Constructor
arg: Box<WebflowPropDataType>, // Normally Passes the Row Constructor
},
TypeConstructor(Vec<String>), // Stores Value of TypeConstructor
RowCons {
label: String, // Stores the label of the Row
#[serde(rename = "type")]
row_con_type: Box<WebflowPropDataType>, // Stores the type of the Row
tail: Box<WebflowPropDataType>,
},
RowEmpty, // For Ending the recursive usage of rowConstructor
}
#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct WebflowRowConDataType {
#[serde(rename = "type")]
val_type: String, // TypeApplication
val: Box<WebflowPropDataType>,
}
This works for a structure like this :
{
"type": "TypeApplication",
"val":{
"con": {
"type": "TypeConstructor",
"val": []
},
"arg": {
"type": "RowEmpty"
}
}
}
but would fail if I try to work with initial example. I know this may be due to the lack of a proper arg type or maybe even the TypeApplication Enum hand is malformed.
I do see that a adjancent typing solution would be enough for most of the times but there are cases as seen in the example structure that there is a third value called system and I am unable to determine what type of approach would help me achieve this type of outcome.
How should I approach this problem in order to generate this type of code.
I am not asking anyone to write me a solution but to give me suggestion as to what my approach should be? Whether you'd know what type of data this is/how to generated this , or even if there are some other library I should look into to manipulate this type of data or maybe look at other approaches.
PS : - My end goal is to be able to generate / serialize this type of JSON code from already contained knowledge of properties and default values of a function/object.

Here are my recommendations:
Use just #[serde(tag = "type")] instead of #[serde(tag = "type", content = "val")]. You will have to handle val manually (extracting the current enum members into separate structs), but this allows you to also handle TypeApplication.system and Element.meta.
This also has the small benefit of reducing the amount of Boxes involved.
Consider whether all of the different cases in WebflowPropDataType can actually occur everywhere it's used. If not (maybe Element can only happen under TypeApplication.val.arg), then you may want to split the enum into multiple so that this is reflected in the type system.
Example for #1:
use serde::{Serialize, Deserialize};
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TypeApplicationVal {
con: WebflowPropDataType, // Normally Passes the Type Constructor
arg: WebflowPropDataType, // Normally Passes the Row Constructor
}
// #[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TypeApplicationSystem {
label: String,
#[serde(rename = "isBindable")]
is_bindable: bool,
// TODO: defaultValue
#[serde(rename = "isUnlinked")]
#[serde(skip_serializing_if = "Option::is_none")]
is_unlinked: Option<bool>,
#[serde(rename = "isDefault")]
#[serde(skip_serializing_if = "Option::is_none")]
is_default: Option<bool>,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct RowConsVal {
label: String, // Stores the label of the Row
#[serde(rename = "type")]
typ: WebflowPropDataType, // Stores the type of the Row
tail: WebflowPropDataType,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ElementMeta {
#[serde(rename = "multiLine")]
multi_line: bool,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum WebflowPropDataType {
TypeApplication {
val: Box<TypeApplicationVal>,
#[serde(skip_serializing_if = "Option::is_none")]
system: Option<TypeApplicationSystem>,
},
TypeConstructor {
val: Vec<String> // Stores Value of TypeConstructor
},
RowCons {
val: Box<RowConsVal>,
},
Element {
meta: ElementMeta,
},
RowEmpty, // For Ending the recursive usage of rowConstructor
}
playground

Related

Add bpmn:Resource in propertiesPanel

Is it possible to add "bpmn:Resource" element in propertiesPanel and edit its attribute? how to do it?
I've already added some properties to property panel based on the property-panel[link] example.
But I have a challenge in adding 'bpmn:Resource' to the properties panel. I don't want it to be added as an extensionElement.
I'd like it to be inside bpmn:Definitions (beside bpmn:Process). Also I'd like to extend the original bpmn:Resource to add some parameters.
So in MyModdle.json I added:
{
"name": "Resource",
"extends": [
"bpmn:Resource"
],
"properties": [
{
"name": "parameters",
"isMany": true,
"type": "MyParameter"
}
]
}, {
"name": "MyParameter",
"properties": [
{
"name": "myParameterType",
"isAttr": true,
"type": "String"
}
{
"name": "myParameterName",
"isAttr": true,
"type": "String"
},
{
"name": "myParameterValue",
"isAttr": true,
"type": "String"
}
]
}
now for example in newElement function of MyResource.js
var newElement = function (type, prop, factory) {
return function (element, extensionElements, value) {
var commands = [];
var resource = getResource(element);
if (!resource) {
var parent = extensionElements;
resource = createResource(parent, bpmnFactory);
console.log('resource', resource);
commands.push(cmdHelper.addAndRemoveElementsFromList(
element,
extensionElements,
'values',
'extensionElements',
[resource],
[]
));
}
var newElem = createResourceParameter(type, resource, bpmnFactory, {
resourceId: 'id-' + value
});
commands.push(cmdHelper.addElementsTolist(element, parameters, prop, [newElem]));
return commands;
};
}
I know this cmdHelper adds 'bpmn:Resource' to extensionElements but I don't know what to use instead!

How do I view the JSON behind a Google Slide?

I want to know what elements of a slide can be changed programmatically; one way to understand what's going on would be to look at the JSON behind slides. I have the slides ID but haven't figured out how to look at it in any way except the standard wysiwyg editor.
For the whole presentation, you can check this documentation.
JSON representation
{
"presentationId": string,
"pageSize": {
object(Size)
},
"slides": [
{
object(Page)
}
],
"title": string,
"masters": [
{
object(Page)
}
],
"layouts": [
{
object(Page)
}
],
"locale": string,
"revisionId": string,
"notesMaster": {
object(Page)
},
}
And for each page, you can refer to REST Resource: presentations.pages.
JSON representation
{
"objectId": string,
"pageType": enum(PageType),
"pageElements": [
{
object(PageElement)
}
],
"revisionId": string,
"pageProperties": {
object(PageProperties)
},
// Union field properties can be only one of the following:
"slideProperties": {
object(SlideProperties)
},
"layoutProperties": {
object(LayoutProperties)
},
"notesProperties": {
object(NotesProperties)
},
"masterProperties": {
object(MasterProperties)
},
// End of list of possible types for union field properties.
}

graphql-ruby: Int isn't a defined input type (on $first)

I’ve got a question I can’t seemingly resolve on my own.
Together with basic Query, Mutation and so on types I’ve made the following type definition:
module Types
UserType = GraphQL::ObjectType.define do
name 'User'
description 'A user'
implements GraphQL::Relay::Node.interface
global_id_field :id
field :email, !types.String, 'Email address'
connection :docs, DocType.connection_type, 'Available docs'
end
end
And I then try to query it with:
query FileListQuery(
$after: String
$first: Int
) {
viewer {
currentUser {
docs(first: $first, after: $after) {
edges {
node {
id
name
__typename
}
cursor
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
}
id
}
id
}
}
And I pass the following as query variables:
{
"first": 1,
"after": null
}
The problem is it bails out with the following:
{
"errors": [
{
"message": "Int isn't a defined input type (on $first)",
"locations": [
{
"line": 3,
"column": 3
}
],
"fields": [
"query FileListQuery"
]
}
]
}
I honestly have no clue why it complains about the Int type…
If I get rid of the problematic $first query variable in the request, it works fine.
This:
query FileListQuery(
$after: String
) {
viewer {
currentUser {
docs(first: 10, after: $after) {
edges {
node {
id
name
__typename
}
cursor
}
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
}
id
}
id
}
}
Produces this:
{
"data": {
"viewer": {
"currentUser": {
"docs": {
"edges": [
{
"node": {
"id": "1",
"name": "First Doc",
"__typename": "Doc"
},
"cursor": "MQ=="
}
],
"pageInfo": {
"endCursor": "MQ==",
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": "MQ=="
}
},
"id": "1"
},
"id": "VIEWER"
}
}
}
Any hints, ideas on how to fix this? I use the graphql gem v1.6.3.
Currently, there seems to be a bug in graphql-ruby that prevents types not explicitly used in a schema from being propagated. Check out this issue on GitHub: https://github.com/rmosolgo/graphql-ruby/issues/788#issuecomment-308996229
To fix the error one has to include an Int field somewhere in the schema. Turns out I haven't had one. Yikes.
This fixed it for me:
# Make sure Int is included in the schema:
field :testInt, types.Int

Get key of dictionary on JSON parse with SwiftyJSON

I want to get "key of dictionary" (that's what I called, not sure if it is right name) on this JSON
{
"People": {
"People with nice hair": {
"name": "Peter John",
"age": 12,
"books": [
{
"title": "Breaking Bad",
"release": "2011"
},
{
"title": "Twilight",
"release": "2012"
},
{
"title": "Gone Wild",
"release": "2013"
}
]
},
"People with jacket": {
"name": "Jason Bourne",
"age": 15,
"books": [
{
"title": "Breaking Bad",
"release": "2011"
},
{
"title": "Twilight",
"release": "2012"
},
{
"title": "Gone Wild",
"release": "2013"
}
]
}
}
}
First of all, I already created my People struct that will be used to map from those JSON.
Here is my people struct
struct People {
var peopleLooks:String?
var name:String?
var books = [Book]()
}
And here is my Book struct
struct Book {
var title:String?
var release:String?
}
From that JSON, I created engine with Alamofire and SwiftyJSON that will be called in my controller via completion handler
Alamofire.request(request).responseJSON { response in
if response.result.error == nil {
let json = JSON(response.result.value!)
success(json)
}
}
And here is what I do in my controller
Engine.instance.getPeople(request, success:(JSON?)->void),
success:{ (json) in
// getting all the json object
let jsonRecieve = JSON((json?.dictionaryObject)!)
// get list of people
let peoples = jsonRecieve["People"]
// from here, we try to map people into our struct that I don't know how.
}
My question is, how to map my peoples from jsonRecieve["People"] into my struct?
I want "People with nice hair" as a value of peopleLooks on my People struct. I thought "People with nice hair" is kind of key of dictionary or something, but I don't know how to get that.
Any help would be appreciated. Thank you!
While you iterate through dictionaries, for instance
for peeps in peoples
You can access key with
peeps.0
and value with
peeps.1
You can use key, value loop.
for (key,subJson):(String, JSON) in json["People"] {
// you can use key and subJson here.
}

Swagger 2.0 - How to Define an Embedded Object

I want to define an object with a key and a value but can't figure out how to define it as a property in a swagger 2.0 definition. Frankly, I am not sure if this is even possible if one wants to be able to define strongly typed clients. However, I figure I'd ask to see if this is even possible/allowable.
Basically, I want to be able to store the following object:
{ "currencies":
{ "usd" : 1.10,
"eur" : 2.25
}
}
But I don't want usd, and eur to have to be defined in the schema. I can do the below but I don't want usd or eur to be predefined. I want it to accept any value for the keys of the object.
"Product": {
"properties": {
"currencies": {
"type": "currencyObj"
},
}
},
},
"currencyObj": {
"id": "currencyObj",
"properties": {
"eur": {
"type": "float"
},
"usd": {
"type": "float"
}
}
}
Swagger 2.0 allows you to define a string to type mapping, you need to use additionalProperties. Use following notation to define a map :
"currencyObj": {
"type": "object",
"additionalProperties": {
"type": "number"
}
}

Resources