Ramda.when always return true using fs - node.js

I am trying to use Ramda.when to execute only if a condition is true but it's always returning true:
const bla2 = path => () => R.when(fs.existsSync(path()), console.log(path()))
Is there anyway to use Ramda.when with fs.existsSync?
edit:
Even set false this is not working:
const bla3 => () => R.when(false, console.log('bla'))
This is the real code:
const moveEnvironmentVarsFile = (oldPath, newPath) => () => R.when(fs.existsSync(oldPath()), fs.renameSync(oldPath(), newPath()))

I don't think R.when is appropriate for what you're trying to do. R.when's purpose is to transform a value, but only if that value matches a condition. It expects you to pass in three things:
A function which checks the condition
A function which does the transformation
A value that you want to send through this process
fs.existsSync can conceivably be used as argument 1, such as the following contrived example which appends "exists" to a string if the file exists:
const result = R.when(
fs.existsSync,
(val) => val + "exists",
"some/file"
);
// result is either some/file or some/fileexists
In real word, I am trying to rename a file using fs. How can I do it using ramda or any functional way in JS?
Honestly, i would just use an if/else and not use Ramda:
const myFunc = (filename) => {
if (fs.existsSync(filename) {
// do something
} else {
// do something else
}
}
If you really want to use ramda to create that code for you, you could use R.ifElse:
const myFunc = R.ifElse(
fs.existsSync,
(filename) => { /* do something */ },
(filename) => { /* do someething else */ }
);

Related

Correct way to organise this process in Node

I need some advice on how to structure this function as at the moment it is not happening in the correct order due to node being asynchronous.
This is the flow I want to achieve; I don't need help with the code itself but with the order to achieve the end results and any suggestions on how to make it efficient
Node routes a GET request to my controller.
Controller reads a .csv file on local system and opens a read stream using fs module
Then use csv-parse module to convert that to an array line by line (many 100,000's of lines)
Start a try/catch block
With the current row from the csv, take a value and try to find it in a MongoDB
If found, take the ID and store the line from the CSV and this id as a foreign ID in a separate database
If not found, create an entry into the DB and take the new ID and then do 6.
Print out to terminal the row number being worked on (ideally at some point I would like to be able to send this value to the page and have it update like a progress bar as the rows are completed)
Here is a small part of the code structure that I am currently using;
const fs = require('fs');
const parse = require('csv-parse');
function addDataOne(req, id) {
const modelOneInstance = new InstanceOne({ ...code });
const resultOne = modelOneInstance.save();
return resultOne;
}
function addDataTwo(req, id) {
const modelTwoInstance = new InstanceTwo({ ...code });
const resultTwo = modelTwoInstance.save();
return resultTwo;
}
exports.add_data = (req, res) => {
const fileSys = 'public/data/';
const parsedData = [];
let i = 0;
fs.createReadStream(`${fileSys}${req.query.file}`)
.pipe(parse({}))
.on('data', (dataRow) => {
let RowObj = {
one: dataRow[0],
two: dataRow[1],
three: dataRow[2],
etc,
etc
};
try {
ModelOne.find(
{ propertyone: RowObj.one, propertytwo: RowObj.two },
'_id, foreign_id'
).exec((err, searchProp) => {
if (err) {
console.log(err);
} else {
if (searchProp.length > 1) {
console.log('too many returned from find function');
}
if (searchProp.length === 1) {
addDataOne(RowObj, searchProp[0]).then((result) => {
searchProp[0].foreign_id.push(result._id);
searchProp[0].save();
});
}
if (searchProp.length === 0) {
let resultAddProp = null;
addDataTwo(RowObj).then((result) => {
resultAddProp = result;
addDataOne(req, resultAddProp._id).then((result) => {
resultAddProp.foreign_id.push(result._id);
resultAddProp.save();
});
});
}
}
});
} catch (error) {
console.log(error);
}
i++;
let iString = i.toString();
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(iString);
})
.on('end', () => {
res.send('added');
});
};
I have tried to make the functions use async/await but it seems to conflict with the fs.openReadStream or csv parse functionality, probably due to my inexperience and lack of correct use of code...
I appreciate that this is a long question about the fundamentals of the code but just some tips/advice/pointers on how to get this going would be appreciated. I had it working when the data was sent one at a time via a post request from postman but can't implement the next stage which is to read from the csv file which contains many records
First of all you can make the following checks into one query:
if (searchProp.length === 1) {
if (searchProp.length === 0) {
Use upsert option in mongodb findOneAndUpdate query to update or upsert.
Secondly don't do this in main thread. Use a queue mechanism it will be much more efficient.
Queue which I personally use is Bull Queue.
https://github.com/OptimalBits/bull#basic-usage
This also provides the functionality you need of showing progress.
Also regarding using Async Await with ReadStream, a lot of example can be found on net such as : https://humanwhocodes.com/snippets/2019/05/nodejs-read-stream-promise/

Mock function without callback as parameter

I have dh.js
const checkDExistsCallback = (err, dResp) => {
if (err)
cbResp.error('failed');
if (dResp.length > 0)
checkDCollectionExists();
else
cbResp.error('Not found.');
};
const checkDCollectionExists = () =>
{
let query = `select sid from tablename where sid = '${objRequestData.dName}' limit 1;`;
genericQueryCall(query, checkDCollCallback);
}
module.exports = {checkDExistsCallback , checkDCollectionExists }
In my dh.test.ts
const dhExport = require("./DensityHookReceive");
dhExport.checkDCollectionExists = jest.fn().mockImplementation(() => {});
test('check req dh is exists', () => {
dhExport.checkDExistsCallback(false, '[{}]');
expect(dhExport.checkDCollectionExists).toBeCalled();
});
In dh.js checkDExistsCallback function is invoked the checkDCollectionExists after satisfied the 'if' condition. When you look into the dh.test.ts file I mocked the checkDCollectionExists function in the beginning, but while running the test it did not invoke the mocked function it invokes the actual function. Can you help me to figure it out?
A function that is used in the same module it was defined cannot be mocked, unless it's consistently used as a method on an object that could be mocked, e.g.
if (dResp.length > 0)
module.exports.checkDCollectionExists();
instead of
if (dResp.length > 0)
checkDCollectionExists();
checkDCollectionExists needs to be either moved to another module, or two functions need to be tested as a single unit. It's database call that needs to be mocked.

DELETE FILES with Node.js

I'm trying to delete some files and then show a message.
EXPECTED OUTPUT
File deleted
Folder Cleared!!!
ACTUAL OUTPUT
Folder Cleared!!!
File deleted
The current code is:
function clearConverted() {
const resp = new Promise(async (resolve) => {
const converted = glob.sync('./converted/*.mp4');
if (converted.length) {
const fs = require('fs');
const promises = converted.map(v => {
fs.unlink(v, () => console.log('File deleted'))
})
Promise.all(promises);
} else {
console.log('No files to delete');
}
resolve();
})
resp.then(console.log('Folder Cleared!!!'))
}
May you help me?
Per my original comments on your question, you have heaps to fix with your code -
Don't use require inside a loop
fs.unlink does not return a Promise.You're probably looking for fsPromises.unlink
What is the explicit Promise constructor anti-pattern and how do I avoid it?
const { unlink } =
require("fs").promises // <-- fsPromises
function clearConverted() {
const converted =
glob.sync("./converted/*.mp4")
if (converted.length === 0)
return Promise.resolve([])
const promises =
converted.map(v => unlink(v).then(_ => v))
return Promise.all(promises)
}
clearConverted() // <-- returns a promise!
.then(deletedFiles => console.log("done! deleted files:", deletedFiles))
// done! deleted files: ./converted/foo.mp4, ./converted/bar.mp4
And see how we removed console.log side effects from the function? This allows our function to collect meaningful data, like the file names, and return a list of deleted files. Because the console.log effect is now outside of clearConverted we can change it, if we wish.
For example, we could simply display the count of deleted files, in a less verbose program -
clearConverted()
.then(deletedFiles =>
console.log("done! deleted %d files.", deletedFiles.length)
)
// done! deleted 9 files.
And we can do more. An obvious improvement now is to make clearConverted a generic function which accepts the path as an argument -
function unlinkFiles (path = "") { // <-- generic name and path parameter
const files =
glob.sync(path)
if (files.length === 0)
return Promise.resolve([])
else
return Promise.all(files.map(f => unlink(f).then(_ => f)))
}
unlinkFiles("./converted/*.mp4") // <-- supply path at call site
.then(deletedFiles => console.log("done! deleted files:", deletedFiles))
.catch(console.error) // <-- don't forget to catch Promises too
Modern features like async allow us to skip some of the ceremony around Promises -
async function unlinkFiles (path = "") { // <-- async keyword
const files =
glob.sync(path)
return files.length === 0
? [] // <-- automatically wrapped in a Promise
: Promise.all(files.map(f => unlink(f).then(_ => f)))
}
Now if you wanted, you could make the function accept a glob result instead of a path -
const unlinkFiles = async (files = []) => // <-- arrow function
files.length === 0
? []
: Promise.all(files.map(f => unlink(f).then(_ => f)))
unlinkFiles(glob.sync("./converted/*.mp4")) // <-- use glob as input
.then(console.log, console.error)
When you detangle the wires, programming can be fun and easy. Sadly, languages like JavaScript also make it easy to shoot yourself in the foot, so there's a lot of misery before enlightenment.
I have other answers involving the fs module and Promises. These additional code examples may help provide additional insight -
Recursively rename files
Recursively read all package.json
Recursively list all subdirectories
When you call Promise.all add .then method there, something likethis:
Promise.all(promises).then((response) => console.log("Folder Cleared")).catch((error) => console.log(error))
And also when you require modules or dependencies, you declare them at the top of the file and not inside functions or loops.

How to mock curry function with Jest?

add.js
export default a => b => a+b;
module.js
import add from './add';
export default {
add1: n => add(1)(n),
};
test/module.js
import add from '../add';
import module from '../module';
jest.mock('../add', () => () => jest.fn());
module.add1(6);
expect(add.mock.calls).toHaveLength(1);
this can be called, but add wouldn't be a mock function, instead add() is a mock function, but the call params were not recorded correctly.
jest.mock('../add', () => () => jest.fn(a => b => a+b));
has also tried this, which doesn't seem to work correctly as well.
jest.mock('../add', jest.fn(a => b => a+b));
this would throw the inline function error
Is there a correct way to mock curry function at the moment?
Simple version should look like this
jest.mock('../add', () => (a) => jest.fn(b => a+b));
So you mock add module with a function that return that when gets called it returns the spy, problem you can't test anything on the spy.
So we need to refactor it so you have the add1 think as a spy in scope of the test
import add from '../add'
jest.mock('../add', () => jest.fn)
const addC = jest.fn()
add.mockImplemetation((a) => {
addC.mockImplementation((b => a+b)
return addC
})
I know this is a bit old but with the following answer I would have saved so much time...
import module from "./module";
const mockOperation = {
add: jest.fn()
};
jest.mock("./add", () => () => {
return mockOperation.add;
});
describe("add ", () => {
it("is called at least once", () => {
module.add1(6);
expect(mockOperation.add.mock.calls).toHaveLength(1);
});
});
A very importante thing: the constant function that you want to mock must start with the word mock. Otherwise it will throw an error.
const mockOperation = {
add: jest.fn()
};
With the mockOperation constant assigned to the add file, by reference is calling to it's add method which is a jest.fn()
I've had to do this a lot recently so I wrote a helper function to help me out.
curryMock = (baseFn, maxCurries) => {
var callIndex = 0
var curries = []
let returnFn
baseFn.mockImplementation((arg) => {
curries[callIndex] = 0
const fn = returnFn(callIndex)
callIndex++
return fn
})
returnFn = (index: number) => {
if (curries[index] < maxCurries) {
curries[index]++
return (arg: any) => {
baseFn.mock.calls[index].push(arg)
return returnFn(index)
}
}
}
}
You pass the function a jest.fn() and curryMock modifies it's implementation so that all the arguments return functions are called with will be added to the original jest.fn().mock.calls array. The second argument specifies how many times to return a function. maxCurries = 0 is for a regular function () => {},
maxCurries = 1is for a regular function() => => {}`, etc.
In your case:
import add from '../add';
import module from '../module';
jest.mock('../add');
curryMock(add)
module.add1(6);
expect(add).toHaveBeenCalledWith(1, 6);
//equivalent to
//expect(add).toHaveBeenNthCalledWith(1, 1, 6);
//if you others to test..
module.add7(4)
expect(add).toHaveBeenNthCalledWith(2, 7, 4)
curryMock is a quick utility function that I wrote for personal use. I will likely clean it up and extend it later, but I hope you get the idea: testing curried functions does not have to laborious.

How to get console.log line numbers shown in Nodejs?

Got an old application, that prints out quite a lot of messages using console.log, but I just can not find in which files and lines console.log is called.
Is there a way to hook into the app and show file name and line numbers?
Having full stack trace for each call is a bit noisy. I've just improved the #noppa's solution to print only the initiator:
['log', 'warn', 'error'].forEach((methodName) => {
const originalMethod = console[methodName];
console[methodName] = (...args) => {
let initiator = 'unknown place';
try {
throw new Error();
} catch (e) {
if (typeof e.stack === 'string') {
let isFirst = true;
for (const line of e.stack.split('\n')) {
const matches = line.match(/^\s+at\s+(.*)/);
if (matches) {
if (!isFirst) { // first line - current function
// second line - caller (what we are looking for)
initiator = matches[1];
break;
}
isFirst = false;
}
}
}
}
originalMethod.apply(console, [...args, '\n', ` at ${initiator}`]);
};
});
It also patches other methods (useful for Nodejs, since warn and error don't come with a stack trace as in Chrome).
So your console would look something like:
Loading settings.json
at fs.readdirSync.filter.forEach (.../settings.js:21:13)
Server is running on http://localhost:3000 or http://127.0.0.1:3000
at Server.app.listen (.../index.js:67:11)
For a temporary hack to find the log statements that you want to get rid of, it's not too difficult to override console.log yourself.
var log = console.log;
console.log = function() {
log.apply(console, arguments);
// Print the stack trace
console.trace();
};
// Somewhere else...
function foo(){
console.log('Foobar');
}
foo();
That will print something like
Foobar
Trace
at Console.console.log (index.js:4:13)
at foo (index.js:10:13)
at Object.<anonymous> (index.js:12:1)
...
A lot of noise in there but the second line in the call stack, at foo (index.js:10:13), should point you to the right place.
All solutions to this question so far rely on splitting and matching the stack trace as a string, which will break in (the unlikely) case the format of that string is changed in the future. Inspired by this gist on GitHub and the other answers here, I want to provide my own solution:
'use strict';
const path = require('path');
['debug', 'log', 'warn', 'error'].forEach((methodName) => {
const originalLoggingMethod = console[methodName];
console[methodName] = (firstArgument, ...otherArguments) => {
const originalPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const callee = new Error().stack[1];
Error.prepareStackTrace = originalPrepareStackTrace;
const relativeFileName = path.relative(process.cwd(), callee.getFileName());
const prefix = `${relativeFileName}:${callee.getLineNumber()}:`;
if (typeof firstArgument === 'string') {
originalLoggingMethod(prefix + ' ' + firstArgument, ...otherArguments);
} else {
originalLoggingMethod(prefix, firstArgument, ...otherArguments);
}
};
});
// Tests:
console.log('%s %d', 'hi', 42);
console.log({ a: 'foo', b: 'bar'});
Unlike the other solutions, this script
outputs no additional lines and
handles string substitutions correctly.
You can color the prefix with chalk or color.js, but I didn't want to introduce dependencies for this here.
The above script uses the V8 API to customize stack traces. The callee is a CallSite object with the following methods in case you want to customize the prefix:
getThis: returns the value of this
getTypeName: returns the type of this as a string. This is the name of the function stored in the constructor field of this, if available, otherwise the object’s [[Class]] internal property.
getFunction: returns the current function
getFunctionName: returns the name of the current function, typically its name property. If a name property is not available an attempt is made to infer a name from the function’s context.
getMethodName: returns the name of the property of this or one of its prototypes that holds the current function
getFileName: if this function was defined in a script returns the name of the script
getLineNumber: if this function was defined in a script returns the current line number
getColumnNumber: if this function was defined in a script returns the current column number
getEvalOrigin: if this function was created using a call to eval returns a string representing the location where eval was called
isToplevel: is this a top-level invocation, that is, is this the global object?
isEval: does this call take place in code defined by a call to eval?
isNative: is this call in native V8 code?
isConstructor: is this a constructor call?
isAsync: is this an async call (i.e. await or Promise.all())?
isPromiseAll: is this an async call to Promise.all()?
getPromiseIndex: returns the index of the promise element that was followed in Promise.all() for async stack traces, or null if the CallSite is not a Promise.all() call.
This answer is a cross-post of an answer I just gave to a similar question as more people might find this page.
I found Dmitry Druganov's answer really nice, but I tried it on Windows 10 (with Node 8.9.4) and it didn't work well. It was printing the full path, something like:
Loading settings.json
at fs.readdirSync.filter.forEach (D:\Users\Piyin\Projects\test\settings.js:21:13)
Server is running on http://localhost:3000 or http://127.0.0.1:3000
at Server.app.listen (D:\Users\Piyin\Projects\test\index.js:67:11)
So I took said answer and made these improvements (from my point of view):
Assume the important line of the stack trace is the third one (the first one is the word Error and the second one is where you place this script)
Remove the current script folder path (given by __dirname, which in my case is D:\Users\Piyin\Projects\test). Note: For this to work well, the script should be on the project's main Javascript
Remove the starting at
Place the file information before the actual log
Format the information as Class.method at path/to/file:line:column
Here it is:
['log','warn','error'].forEach((methodName) => {
const originalMethod = console[methodName];
console[methodName] = (...args) => {
try {
throw new Error();
} catch (error) {
originalMethod.apply(
console,
[
(
error
.stack // Grabs the stack trace
.split('\n')[2] // Grabs third line
.trim() // Removes spaces
.substring(3) // Removes three first characters ("at ")
.replace(__dirname, '') // Removes script folder path
.replace(/\s\(./, ' at ') // Removes first parentheses and replaces it with " at "
.replace(/\)/, '') // Removes last parentheses
),
'\n',
...args
]
);
}
};
});
And here's the new output:
fs.readdirSync.filter.forEach at settings.js:21:13
Loading settings.json
Server.app.listen at index.js:67:11
Server is running on http://localhost:3000 or http://127.0.0.1:3000
Here's the minified-by-hand code (240 bytes):
['log','warn','error'].forEach(a=>{let b=console[a];console[a]=(...c)=>{try{throw new Error}catch(d){b.apply(console,[d.stack.split('\n')[2].trim().substring(3).replace(__dirname,'').replace(/\s\(./,' at ').replace(/\)/,''),'\n',...c])}}});
Slightly modified version of noppa's answer, this version will output something like:
/file/in-which/console/is/called.js:75:23
The stuff you want to log.
This is clean and convenient (especially for use in VSCode - which will turn the file path into a link).
const { log } = console;
function proxiedLog(...args) {
const line = (((new Error('log'))
.stack.split('\n')[2] || '…')
.match(/\(([^)]+)\)/) || [, 'not found'])[1];
log.call(console, `${line}\n`, ...args);
}
console.info = proxiedLog;
console.log = proxiedLog;
// test
console.log('Hello!');
The snippet will only work well in a NodeJS environment…
Appends the line number to the end of the log
const stackTrace = function () {
let obj = {}
Error.captureStackTrace(obj, stackTrace)
return obj.stack
}
const getLine = function (stack) {
let matchResult = stack.match(/\(.*?\)|\s.+/g) || []
let arr = matchResult.map((it) => {
return it.split(' ').pop().replace(/\(|\)/g, '')
})
return arr[1] ?? ''
}
const log = function (...args) {
let stack = stackTrace() || ''
let matchResult = getLine(stack)
let line = matchResult
for (var i in arguments) {
if (typeof arguments[i] == 'object') {
// util.inspect(arguments[i], false, 2, false)
arguments[i] = JSON.stringify(arguments[i])
}
}
arguments[i] += ' ' + line
console.log.apply(console, arguments)
}
log("test")
Simple & exhaustive solution if you want to temporarily find the origin of logs:
{
const logOriginal = process.stdout.write
// #ts-ignore
const log = (msg) => logOriginal.call(process.stdout, msg + '\n')
;['stdout', 'stderr'].forEach((stdName) => {
// #ts-ignore
var methodOriginal = process[stdName].write
// #ts-ignore
process[stdName].write = function (...args) {
log('LOG:')
// #ts-ignore
methodOriginal.apply(process[stdName], args)
// #ts-ignore
log(new Error().stack.replace(/^Error/, 'LOGGED FROM:'))
}
})
Error.stackTraceLimit = Infinity
}
const showName = (name) => {
return
console.log(name)
}
showName(“Crush”)

Resources