How to create a typescript union type with values from a JSON object - json

Suppose I have this JSON object
[
{ "label": "The entire place", "value": "entire_place" },
{ "label": "A shared room", "value": "shared_room" },
{ "label": "A private room", "value": "private_room" },
]
Those represent the possible values of a dropdown menu. The label is what the user sees, and the value is what's stored in the database.
However, I also need to create a type as follows:
type Property = "entire_place" | "private_room" | "shared_room";
How can I do so without defining the data twice?
I don't want to change the type and JSON object every time I need to add a new possible values.
Any ideas how to do so? If it's not possible, what's a better alternative to store data (along their label) and use it for validation.

First, you need to declare your array as a const, that way typescript generates the specific values rather than just string. Then you can use typeof and index the array with number and lastly value:
const data = [
{ label: 'The entire place', value: 'entire_place' },
{ label: 'A shared room', value: 'shared_room' },
{ label: 'A private room', value: 'private_room' },
] as const;
type Property = typeof data[number]['value'];
Declaring it as a const does mean you can't modify the array, which is a good thing. If you want to keep it entirely in sync with the array, I don't believe that's possible.

Related

JSON Schema - How to limit an object to specific name, with value type 'boolean', without using regex

I want to record data from checkbox inputs, for example:
{
client 1: false,
client 2: true,
client 3: false,
}
or
{
dogs: true
cats: true
horses: false
}
I want to create simple JSON Schemas for these, and would prefer to use a system where I don't have to learn/type/read complicated regex. The following works quite nicely for example 1:
"type": "object",
"patternProperties": {
"^Client [1-3]$": {
type: "boolean",
},
},
"additionalProperties": false,
Unfortunately, it will be complicated when the object properties don't follow a simple pattern, as in example 2. Is there a way to strictly specify the object properties in an array, and also specify the value type? I want to limit the object property names only to the array. So I want something like this pseudo schema:
"additionalProperties": false,
"propertyNames": ["Client 1", "Client 2", "Client 3"],
"allValuesToBe": "boolean"
(I made the last keyword up, but want something like that.) This would accept/reject the following:
client 1: false, // accept
foobar: true, // reject, bad prop name
client 3: 123, // reject, bad value
additionalProperties doesn't have to be a boolean - you can put a normal schema there. So as long as all your properties in this object follow the same guidelines, you can do:
"propertyNames": { "enum": ["Client 1", "Client 2", "Client 3"] },
"additionalProperties": { "type": "boolean" }

Is there a way to create automatically Angular reactive form using just a json schema?

I am creating Angular application including a reactive form.
I also have a json schema file that should be addressed by that form, including both properties as form fields, and rules as form validation (simple and cross validation).
JSON schema: A and C required, B just required if A2
{
"$schema": "...",
"$id": "...",
...
"properties": {
"A": {
"description": "..."
"type": "string"
"enum": [
"A1",
"A2",
"A3"
]
},
"B": {
"description": "..."
"type": "string"
"enum": [
"B1",
"B2",
"B3"
]
},
"C": {
"description": "..."
"type": "string"
"enum": [
"C1",
"C2",
"C3"
]
},
},
"required": [
"A",
"C"
],
"allOf": [
{
"if": {
"properties": {
"A": {
"const": "A2"
}
}
},
"then": {
"required": [
"B"
]
}
}
]
}
Angular form.component.ts
...
myForm = new FormGroup(
{
'A': new FormControl('', Validators.required),
'B': new FormControl('', ),
'C': new FormControl('', Validators.required)
},
{
validators: [myFirstValidator]
}
);
cross-val.ts
import { ValidationErrors, ValidatorFn, FormGroup, AbstractControl } from "#angular/forms";
export const myFirstValidator: ValidatorFn =
(formGroupControl: AbstractControl): ValidationErrors | null => {
const A = formGroupControl.get('A')
const B = formGroupControl.get('B')
if ( A!.value == "A2" && B!.value === "") {
return { Brequired: true }
}
return null
};
Is there a way to create automatically the reactive form using just the json schema? At least, is there a way to create the cross validation file from the json schema?
Yes it is, but it's not simple.
Step 0: Create a schema that you can easily parse
You already did that, though you might need to adjust it after you are done to be easily usable.
Step 1: Create custom validator factories
First you'll have to create factories for each and every validator that you want to be able to set via your JSON. Those factories must accept the values that the validator should check against.
For example if you want to use Angulars Validators.maxLength you'd have to create something like this:
export const maxLengthValidatorFactory = validation => Validators.maxLength(validation.value);
After this is done you have to group all your validators in a way that can be easily accessed by generic functions. This would leave you with something like this:
export const VALIDATOR_FACTORIES = {
maxLength: maxLengthValidatorFactory,
...
};
// for better typing
export declare type ValidatorKey = keyof typeof VALIDATOR_FACTORIES;
Step 2: Create the functionality to parse the JSON into Validators
Use Angulars Validators.compose() function. In there you can use the validations defined in your JSON and map them to the validator factories created in Step 1.
You can create the validator function in there by using the array accessor of the VALIDATOR_FACTORIES defined above.
Step 3: Create the form control
Now that you have your validator function(s) parsed in a way Angular can use you can go and create your FormControls. For that you can simply use the new FormControl() function and pass to it your parsed validator(s) as a parameter.
Step 4: Create the form group
Last you can go and put all the FormControls you just created into a FromGroup. You may create that one again by iterating over your JSON to create the keys that belong to the FormControls, if you want to have them named in a specific way.
Step 5: Create the HTML inputs
Now that you have your form group set up you can again iterate over the JSON the create the fitting HTML input elements.
By then setting the created FormGroup on their <form> and using the names for the controls that you already used inside the FormGroup you link everything up.

Unable to parse JSON list in Azure Data Factory ADF

In my datafactory pipeline I hava a web activity which is giving below JSON response. In the next stored procedure activity I am unable parse the output parameter. I tried few methods.
I have set Content-Type application/json in web activity
Sample JSON:
Output
{
"Response": "[{\"Message\":\"Number of barcode(s) found:1\",\"Status\":\"Success\",\"CCS Office\":[{\"Name\":\"Woodstock\",\"CCS Description\":null,\"BranchType\":\"Sub CFS Office\",\"Status\":\"Active\",\"Circle\":\"NJ\"}]}]"
}
For parameter in stored procedure activity:
#json(first(activity('Web1').output.Response))
output - System.Collections.Generic.List`1[System.Object]
#json(activity('Web1').output.Response[0])
output - cannot be evaluated because property '0' cannot be selected. Property selection is not supported on values of type 'String'
#json(activity('Web1').output.Response.Message)
output - cannot be evaluated because property 'Message' cannot be selected. Property selection is not supported on values of type 'String'
Here is what I did:
I created a new pipeline, and created a parameter of type 'object' using your 'output' in its entirety:
{ "Response": "[{\"Message\":\"Number of barcode(s) found:1\",\"Status\":\"Success\",\"CCS Office\":[{\"Name\":\"Woodstock\",\"CCS Description\":null,\"BranchType\":\"Sub CFS Office\",\"Status\":\"Active\",\"Circle\":\"NJ\"}]}]" }
I created a variable and setVariable activity. Variable is of type string. The dynamic expression I used is:
#{json(pipeline().parameters.output.response)[0]}
Let me break down and explain. The {curly braces} were necessary because variable is of type string. You may not want/need them.
json(....)
was necessary because data type for the value of 'response' was left as a string. Whether it being string is correct behavior or not is a different discussion. By converting from string to json, I can now do the final piece.
[0]
Now works because Data Factory sees the contents as an objects rather than string literal. This conversion seems to have been applied to the nested contents as well, because without the encapsulating {curly braces} to convert to string, I would get a type error from my setVariable activity, as the variable is of type string.
Entire pipeline code:
{
"name": "pipeline11",
"properties": {
"activities": [
{
"name": "Set Variable1",
"type": "SetVariable",
"dependsOn": [],
"userProperties": [],
"typeProperties": {
"variableName": "thing",
"value": {
"value": "#{json(pipeline().parameters.output.response)[0]}",
"type": "Expression"
}
}
}
],
"parameters": {
"output": {
"type": "object",
"defaultValue": {
"Response": "[{\"Message\":\"Number of barcode(s) found:1\",\"Status\":\"Success\",\"CCS Office\":[{\"Name\":\"Woodstock\",\"CCS Description\":null,\"BranchType\":\"Sub CFS Office\",\"Status\":\"Active\",\"Circle\":\"NJ\"}]}]"
}
}
},
"variables": {
"thing": {
"type": "String"
}
},
"annotations": []
}
}
I had the similar problem and this is how I resolved the issue.
I passed the value of Response as a string to lookup activity which calls a stored procedure in Azure SQL. The stored procedure parses the string using Json_value and return the individual key, value as a row. Now output of lookup activity can be accessed directly from preceding activities.

d3js dynamically accessor children

I am creating with the d3 tree layout a tree. My data is as already as a tree but not with the d3js format ( {name: "", "childrend": []} ) but with a simple JSON tree format like :
[{
"A": [{
"AA": []
}, {
"AB": []
}, {
"B": [{
"BA": []
}, {
"BB": []
}]
}]
}]
Of course, the data is not with "A" and "B", is just for making the JSON more clear and give just a part of my data. (My data not following a pattern as the exemple)
I saw i could use tree.children() to change the name, but how can i dynamically do it ?!
I need to use this tree format with d3 tree layout.
So since you can write an accessor function, you can make it smarter than just returning a single property.
The function can be made to check each object key and return it if the corresponding value contains children.

Freebase: working with "namespace-prefix key" Json Object

I have made a request to freebase API, and the query is:
{
"id" : "/m/01f8mn",
"key" : [{
"namespace" : "/wikipedia/en_id",
"value" : null
}],
"key" : [{
"namespace" : "/authority/mobygames/game",
"value" : null
}]
}​
And I got the answer from Freebase:
{
"code": "/api/status/ok",
"result": {
"id": "/m/01f8mn",
"key": [{
"namespace": "/wikipedia/en_id",
"value": "213502"
}],
"ns0:key": [{
"namespace": "/authority/mobygames/game",
"value": "prince-of-persia"
}],
"ns1:key": [{
"namespace": "/authority/giantbomb/game",
"value": "61-2561"
}]
},
"status": "200 OK",
"transaction_id": "cache;cache03.p01.sjc1:8101;2012-05-20T18:37:04Z;0060"
}
As you can notice, there is a "namespace prefix" key in the result ("ns0:key", "ns1:key")
The question is: how can I handle this with Javascript Object? Can anyone help?
When accessing properties with special characters in the name, access it as you would an associative array property:
yourObject.result["ns0:key"]
Since the namespace and value properties are stored inside of an object that is the first index of an array, to access the namespace and value, use the following syntax:
yourObject.result["ns0:key"][0].namespace
yourObject.result["ns0:key"][0].value // contains "prince-of-persia"
yourObject.result["ns1:key"][0].namespace
yourObject.result["ns1:key"][0].value // contains "61-2561"
Your initial query isn't valid JSON (the two "key" keys will overwrite each other), so I suspect there's an intermediary software layer involved (perhaps Freebase's query editor?).
If it would help to be able to control the prefixes (they're not really namespaces), you can make them up yourself to suit you. Use "key" and "other:key" or whatever scheme works for you. You could also re-write the query using the |= operator so you can specify both namespaces in a single key clause (e.g. "key":[{"namespace|=" :[ns1,ns2]}]).
for ( key in freebaseResult.result ) {
var i, resultArray = freebaseResult.result[key];
for ( i = 0; i < resultArray.length; i++ ) {
alert( resultArray[i].namespace + ": " + resultArray[i].value );
}
}