Ramda: access input object's properties inside R.ifElse() function call - javascript

I have this existing function:
const inferProcessingError = R.ifElse(
R.propEq('conversionJobStatus', 3),
R.always('Last Process failed with error; please contact DevOps'),
R.always(null)
);
which is called like this:
const msg = inferProcessingError(jobStruct || {});
with this jobStruct:
{"id":9,"mediaGroupId":1000000,"conversionJobStatus":3,
"errorDetails": {
"Cause": {
"errorMessage": "MediaConvert Job Failed with ERROR status: ERROR Video codec [indeo4] is not a supported input video codec",
},
"Error": "Error",
}
}
and I need to create an error message string which includes the data from the Cause.errorMessage element.
This would be dead simple with a native JavaScript function, but I'm learning Ramda and want to just modify the existing code to include in the error message.
An R.prop('Cause')['errorMessage'] could work except that I can't figure out how to reference the jobStruct that was passed in to the inferProcessingError statement.
I can see that the R.ifElse and subsequent Ramda functions are able to get that reference, but when I embed an R.prop('Cause') in the error message string, it resolves to a function and not the value of the Cause element because it seems to be waiting for the data structure.
So...how do I gain access to the jobStruct reference? (arguments is not defined here).
UPDATE:
I can get this to work by referencing the original jobStruct as in R.Prop('ErrorDetails', jobStruct)['Cause']['errorMessage'] but that seems rather kludgy to me...
BUT if the call to inferProcessingError is actually inside a map statement and references an element in a larger structure, then the map index is not available to reference the data structure for the R.prop.

Perhaps you could use the pipe and path methods to achieve this "the ramda way".
Begin by using ramda's path() function to extract the nested errorMessage value from the input jobStruct object. Next, enclose that in a pipe() that transforms the extracted message into a string formatted with a custom error prefix:
const incCount = R.ifElse(
R.propEq('conversionJobStatus', 3),
/* Evaluate this pipe if the error case is satisfied */
R.pipe(
/* Path to extract message from input object */
R.path(["errorDetails", "Cause", "errorMessage"]),
/* Prefix string to extracted error message */
R.concat('Custom error prefix:')),
R.always('')
);
incCount({"id":9,"mediaGroupId":1000000,"conversionJobStatus":3,
"errorDetails": {
"Cause": {
"errorMessage": "MediaConvert Job Failed with ERROR etc etc",
},
"Error": "Error",
}
});
Here's a working example - hope that helps!
Update
Thanks to #customcommander for the suggestion to use concat for the string prefix, as well as returning an empty string value for the second branch

Related

JS ERROR: Error: Expected an object of type GCancellable for argument 'cancellable' but got type string

I'm trying to follow this tutorial.
Basically, I want to create my custom function that creates a folder if it not exists.
var makeDir = (path) => {
const file = Gio.file_new_for_path(path);
if (file.query_exists(path)) {
print(`Dir already exists ${path}`);
return;
}
print(`My Path: ${path}`);
// file.make_directory(path);
};
When I run this code I'm receiving an error:
Gjs-CRITICAL **: 17:35:17.161: JS ERROR: Error: Expected an object of type GCancellable for argument 'cancellable' but got type string
In the documentation I see that GCancellable is optional. So I have no idea why my code does not work. Haw can I make it work?
In the C documentation, "optional" means something else than it usually does in JS: it means it's optional to pass a real pointer as that argument, and you may also pass NULL.
The error message is complaining about a string because query_exists() does not take a path string argument. Check the JS documentation for the list of arguments accepted in JS: you should call file.query_exists(null).

javascript passing a function object to a web worker - ERROR DataCloneError could not be cloned

I need to use a web worker to open a separate thread an do some heavy CPU task.
I would need to task the web worker with a function call and arguments and then get the return, so I went for:
funcs.js
export default function add(args) {
return args[0] + args[1];
}
main.js
import add from './funcs.js';
// [...]
this.worker.postMessage({func: add, args: [7, 3]});
then runtime error:
DataCloneError: Failed to execute postMessage on Worker: function add(args) {
return args[0] + args[1];
}
could not be cloned.
It seems the worker.postMessage method only allow string to be passed,
any idea how I can work this around simply and elegantly?
About postMessage
postMessage documentation give a clear definition about what can or cannot be send to a worker:
postMessage accept only value or JavaScript object handled by the structured clone algorithm, which includes cyclical references.
Looking at the structured clone algorithm, it accept :
All primitive types (However, not symbols), Boolean object, String object, Date, RegExp (The lastIndex field is not preserved.), Blob, File, FileList, ArrayBuffer, ArrayBufferView (This basically means all typed arrays like Int32Array etc.), ImageBitmap, ImageData, Array, Object (This just includes plain objects (e.g. from object literals)), Map, Set
But unfortunately :
Error and Function objects cannot be duplicated by the structured clone algorithm; attempting to do so will throw a DATA_CLONE_ERR exception.
So function is definitely not an option. A simple solution would be to import add directly in your worker.js file, and replace func by a string.
Javascript
this.worker.postMessage( {func: 'ADD', args:[7, 3]} );
worker.js
import add from './funcs.js';
onmessage = function(event) {
const action = event.data;
switch (action.func) {
case 'ADD': {
postMessage({
result: add(action.args)
});
}
break;
....

Object is possibly 'undefined' typescript

I am trying to access the value from an object. But I get the following error.
Object is possibly 'undefined' typescript
My TypeScript code:
import { SqlClient } from 'msnodesqlv8';
declare var require: any;
const sql: SqlClient = require('msnodesqlv8');
const connectionString =
'server=.,1433;Database=emps;Trusted_Connection=Yes;Driver={SQL Server Native Client 11.0}';
const query = 'SELECT * FROM [dbo].[sample] WHERE id = 117';
sql.query(connectionString, query, (err, rows) => {
console.log(rows); // this works fine, but when i try to access its value using object key, it fails
console.log(rows[0].Id); // this fails
});
This works fine in JavaScript. What is the TypeScript way of doing it.
You're getting that error because if the rows array doesn't contain any elements, then rows[0] will be undefined. Two possible solutions:
1) Check that it actually has data, e.g.
if (rows[0]) {
console.log(rows[0].Id)
}
2) Disable the strict or strictNullChecks option in your tsconfig.json (see more here). This will silence the error, but you'll get a runtime error if it actually is undefined, so you may want to check the value instead unless you're absolutely certain it will always have data.

JasmineJS 'isNot' property

Real quick about jasmine.addMatchers. With the latest Jasmine build from git, it appears as though the format for doing custom matchers is vastly different than code I'm seeing in the 'Jasmine JavaScript Testing' book. In the book it has code such as:
this.actual or maybe even this.isNot
The new format is something like:
compare: function (actual, expected) {
return {
pass: some true or false statement...
}
}
So, in this case, the 'this.actual' is actually the passed in argument 'actual', which is cool. How about accessing the isNot property if we're calling a new matcher such as:
expect(investment).not.toBeAGoodInvestment();
So, inside the body of 'toBeAGoodInvestment', we should be able to access the 'isNot' property. Not sure how to do that with the new format. I figured out how to set the this.message from the old way to the new way as in:
return {
pass: some statement...,
message: 'some message'
}
The message we would want to have show up in the jasmine reporter would be dynamic based on whatever the 'isNot' is set to.
After digging around in the actual Jasmine.js source, I found out where the arguments were getting passed into custom matcher's compare function, and indeed, the 'isNot' was not making it's way in at all. The 'this.isNot' was available in the context of the 'Expectation.prototype.wrapCompare' function within the Jasmine source itself but where it was really needed was the custom matcher I created.
So now in this wrapCompare function, I simply added the args.push statement within the 'if' statement as in:
if (this.isNot) {
//-- Added this line
args.push(this.isNot);
matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
}
Now, calling the matcher, I can do this:
expect(investment).not.toBeAGoodInvestment();
And then the actual matcher it will look something like this:
toBeAGoodInvestment: function () {
return {
compare: function (actual, isNot) {
return {
pass: actual.isGood(),
message: 'Expected investment to be a ' +
((isNot) ? 'bad' : 'good') + ' investment'
}
}
};
}
Nice little research task here to figure out what Jasmine was doing behind the scenes.
Any other way to get the 'isNot' injected into the compare function, let me know.

Alfresco JavaScript - How to get list of allowed values of a node property?

I'm doing something like this:
document.properties["my:customProperty"] = getSomehowTheProperty(document);
my:customProperty is a string, which has some allowed values in the content model.
How can I get the allowed values from the content model, so that I don't have to store them in a JavaScript array inside the script?
Or how else can I check, that the function getSomehowTheProperty returned an allowed value?
I tried to wrap it with try-catch:
try {
document.properties["my:customProperty"] = getSomehowTheProperty(document);
document.save();
} catch (e) {
document.properties["my:customProperty"] = "Default Value";
document.save();
}
But it looks like integrity is checked and th error is thrown at the end of executing the script, not inside the try block.
Googling "alfresco js allowed values of node properties" and similar queries gives me nothing.
In order to get that sort of information, you'll have to use the DictionaryService to get the PropertyDefinition
Off the top of my head, you'll want to do something like:
QName customPropertyQ = QName.createQName("my:customProperty", namespaceService);
PropertyDefinition customPropertyT = dictionaryService.getProperty(customPropertyQ);
List allowedValues = customPropertyT.getConstraints();
That'd be in Java, see this blog post for details on how to work with the DictionaryService from JavaScript

Categories