String with a variable that can be replaced (php's sprintf equivalent) - javascript

I have a class that looks like below
interface IParams: {
academicYearId: number;
// Other Params
};
export class myClass() {
function1() {
const url = `api/accounts/academic-year/${academicYearId}/financial-plan`;
// Function 1 Functionality
}
function2() {
const url = `api/accounts/academic-year/${academicYearId}/financial-plan`;
// Function 2 Functionality
}
function3() {
const url = `api/accounts/academic-year/${academicYearId}/financial-plan`;
// Function 2 Functionality
}
}
To reduce on the repetition I made url a property
interface IParams: {
academicYearId: number;
// Other Params
};
export class myClass({academicYearId}: ) {
url = `api/accounts/academic-year/:id/financial-plan`;
urlWithId = (academicYearId: number) => this.url.replace(':id', academicYearId )
function1() {
const url = this.urlWithId(academicYearId)
// Function 1 Functionality
}
function2() {
const url = this.urlWithId(academicYearId)
// Function 2 Functionality
}
function3() {
const url = this.urlWithId(academicYearId)
// Function 2 Functionality
}
}
The above approach works but am I was wondering if there is a better way I can approach the below two lines other than setting a part of the string to ':id' and then replace that part with the id value. Something like in php's sprintf
url = `api/accounts/academic-year/:id/financial-plan`;
urlWithId = (academicYearId: number) => this.url.replace(':id', academicYearId )

String interpolation
It's a common approach for doing that like below:
urlWithId = (academicYearId) => `api/accounts/academic-year/${academicYearId}/financial-plan`;

Related

why does the property of the external function inherit to the private variable of the javascript function

Try to use functional programming to create an object with external functions to reduce memory usage.
The function is
//increment no of test cases
function incrNoOfTestCases(inputObj){
let hits = inputObj.hits;
console.log(`function says: ${hits}`)
return {...inputObj, hits: (hits || 0) + 1};
}
The creator function is
const test = function(testDecription){
let state = {hits:0};
state.getState = ()=> testDecription;
state.incHits = () => state = incrNoOfTestCases(state);
state.getHits = () => state.hits || 0;
return state;
}
When I do the following test, I can change the hits by assigning a property with to the function.
test1.incHits().hits=10; //mutable!!
console.log(test1.getHits()); //gives 10
console.log(test1.incHits().hits); //gives function says: 10 and then 11
test1.hits=20; //immutable
console.log(test1.getHits()); //gives 10
I tried various alternatives, finally came up with declaring the function to increment the testcases in the creator function. I am looking for an explanation why the property is mutable not for a working case.
In the first version the function was
function incrNoOfTestCases(inputObj){
return {...inputObj, hits: (inputObj.hits || 0) + 1};
}
In this case I also expected the inputObj.hits not to be mutable by incrNoOfTestCases.hits, but wasn't either.
It seems JavaScript firstly assigns incrNoOfTestCases.hits to state before executing the function. Is this correct? Can you explain why?
There is nothing functional about this code. In functional programming you don't want small logical units to handle their state independently. That's OOP. Using a closure is just the same as using a class if you mutate the value.
This is more functional although it probably doesn't work the way you would like.
const Test = (description, hits = 0) => ({
getState: () => description,
incHits: () => Test(description, hits + 1),
getHits: () => hits
})
const test1 = Test('description')
const test2 = test1.incHits(); // incHits returns a new instance of Test
console.log(test2.getHits())
And this would have done the same thing
class Test {
constructor(description, hits = 0) {
this.description = description;
this.hits = hits;
}
static of (description) { return new Test(description) }
getState () { return this.description}
incHits () { return new Test(this.description, this.hits + 1); }
getHits () { return this.hits }
}
const test1 = Test.of('description');
const test2 = test1.incHits();
Yet another way to do it
const Test = (description, hits = 0) => ({ description, hits, type: 'Test' });
export const getState = ({ description }) => description;
export const incHits = ({ description, hits }) => Test(description, hits + 1);
export const getHits = ({ hits }) => hits;
export const of = (description) => Test(description);
import * from './Test'
const test1 = Test.of('description');
const test2 = Test.incHits(test1);

Get the names of the parameters of the wrapped function

I want to use the methods of the Minio class without specifying all their parameters, but substituting some of the parameters automatically. How do I do it...
I get all the class methods from the prototype of the Minio class and dynamically create wrappers for them in my class.
For each wrapper method, I get the parameter names from the original method of the Test class.
If there is one in the list of parameters that I want to omit when calling my wrapper method, then I add it to the list of arguments and call originalMethod.apply(this.minioClient, args).
Everything was fine until there were methods that were already wrapped.
I need to get the parameter list of the bucketExists method from outside the Minio class. Any idea how to get parameter names from such a wrapped method?
// minio/dist/main/helpers.js
exports function promisify(fn){
return function(){
const args = [...arguments];
fn.apply(this, args);
}
}
// minio/dist/main/minio.js
class Minio{
bucketExists(bucketName){
return bucketName;
}
methodThatNotWrappedByPromisifyAndWorksFine(bucketName){
return bucketName;
}
}
module.exports = Minio;
Minio.prototype.bucketExists = (0,helpers.promisify)(Minio.prototype.bucketExists)
I want to give an instance of my class with methods wrapped from the original class link the ability to work with only one bucket, that was passed to the my class constructor, without the ability to specify some other one after initialize.
My wrapper
const proxyHandler = () => {
return {
apply: (target, thisArg, argumentsList) => {
const funcParams = getMethodParamNames(target.source ? target.source.functionForWrap : target);
const bucketNameIndex = funcParams.indexOf("bucketName");
const regionNameIndex = funcParams.indexOf("region");
if (bucketNameIndex >= 0) {
argumentsList.splice(bucketNameIndex, 0, this.bucket.name);
}
if (regionNameIndex >= 0) {
argumentsList.splice(regionNameIndex, 0, this.bucket.region);
}
try {
return target.apply(this.minioClient, argumentsList);
} catch (error) {
logger.engine.error(`S3 '${this.bucket.name}' ${target} error: ${error.message}`, error.stack);
}
},
}
}
getMethods(this.minioClient).forEach(func => {
this[func] = new Proxy(this.minioClient[func], proxyHandler());
})
Solved the problem by overriding the method wrapper like this.
const MinioHelpers = require('minio/dist/main/helpers');
const origMinioPromisify = MinioHelpers.promisify;
MinioHelpers.promisify = (functionForWrap) => {
console.log("PATCHED!", functionForWrap);
var fn = origMinioPromisify(functionForWrap);
//from this i'll get all need information about wrapped function
fn.source = {
functionForWrap,
promisify: origMinioPromisify,
}
return fn
}
var Minio = require('minio');

Set Function name as String - Javascript

Hey I'm trying to create a String Const with the value of the function wrapping it
Const url = 'mainapiurl.com/api/'
export function GetPointsStoreBenefits() {
const urlExtention = // I want to name it automatically like the function (GetPointsStoreBenefits)//
FullUrl = url + urlExtention
I need to make a lot of calls so I was wondering is it the best practice? any suggestions?
the concept supposed to be dynamic code like this
const urlExtention = thisfunction.name
The easiest option is to make a higher order function that you can derive your other functions from:
const url = 'mainapiurl.com/api/'
function makeFunction(urlExtention) {
return function() {
const fullURL = url + urlExtention;
/* do something */
console.log("full URL is:", fullURL);
}
}
/* export */ const GetPointsStoreBenefits = makeFunction("GetPointsStoreBenefits");
/* import GetPointsStoreBenefits ... */
GetPointsStoreBenefits();
Function object have a name property, which contains the function name.
So in your case you can do something like:
export function GetPointsStoreBenefits() { }
const urlExtention = GetPointsStoreBenefits.name;
See also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

how to export Reflect.defineProperty()?

So I've been using a bunch of these in my main javascript initiation file, there's like 20-30 of these that I need. Is there a way that I can export these from a different files so I can clear up my main file?
Reflect.defineProperty(numerator, 'getBalance', {
value: function getBalance(id) {
const TEMPLATEUser = numerator.get(id);
return TEMPLATEUser ? TEMPLATEUser.balance : 0;
},
});
I think you can create a function to abstract away what you're doing. Suppose you define this function in a file called file1.js and you want to use it in file2.js.
// file1.js
module.exports.defineGetBalance = obj => {
Reflect.defineProperty(obj, 'getBalance', {
value: function getBalance(id) {
const TEMPLATEUser = obj.get(id);
return TEMPLATEUser ? TEMPLATEUser.balance : 0;
},
});
};
Now you can call defineGetBalance() as many times as you can, you just have to pass the object you want to assign that getBalance function into.
// file2.js
const { defineGetBalance } = require('./file1');
// ...
defineGetBlance(obj1);
defineGetBlance(obj2);
// now both obj1 and obj2 have a getBalance() function
const balance1 = obj1.getBalance(id1)
const balance2 = obj2.getBalance(id2)
// you a for loop if you can
for (const obj of arrObj) {
defineGetBalance(obj);
}
// ...

read parameters from url-string and execute proper function

I create some kind of "routing system" for RestfulAPI in function runUrl - on input I put url which contains some parameters (ID values) and I want to find this url in routes array, execute function given for that route with this parameters, and return that result as runUrl result.
function runUrl(url) {
return projects('f505ecfb74','5e735f505c'); // hardcoded mockup
// Question: how this function should look like ?
}
let routes = [
['/cars', cars ],
['/companies/:companyId/cars/:carId/projects', projects ],
['/companies/:companyId/room/:roomId', rooms ],
//...
];
// list of funtions to execute for given url
function cars() { return ["car1","car2"]; }
function projects(companyId,carId) { return [`proj-${companyId}`,`proj-${carId}`]; }
function rooms(companyId,roomId) { return `room-${companyId}-room-${roomId}` }
// ... (more functions)
// TEST
console.log(runUrl('/companies/f505ecfb74/cars/5e735f505c/projects'));
So far I write below function - but I have headache and it doesn't work
function runUrl(url) {
let route = routes.find( r=> url.match(r[0]) );
if(route) {
return route[1](url.match(route[0]));
}
return null;
}
The parameters values are alpha-numeric strings, parameters names in routes array start with : and then are alpha-numeric strings too. The number of parameters is arbitrary.
How function runUrl should look like?
I don't think you can do it with the match method because it's not meant to be equal between two strings, but I think I found an elegant solution to your problem, maybe it will help you :
let routes = [
['/cars', cars ],
['/companies/:companyId/cars/:carId/projects', projects ],
['/companies/:companyId/room/:roomId', rooms ],
];
function runUrl(url) {
let arrUrl = url.split('/') // it will make an array with any value after /
let route = routes.find( r=> arrUrl.length === r[0].split('/').length ); // it supposed to be equal by length
if(route) {
let params = arrUrl.filter(p => p && p.match(/\d+/)) // it will cut only the ids (string with number)
return route[1](params);
}
return null;
}
// list of funtions to execute for given url
function cars() {
return ["car1","car2"];
}
function projects(array) {
return [`proj-${array[0]}`,`proj-${array[1]}`];
}
function rooms(array) {
return `company-${array[0]}-room-${array[1]}`;
}
// ... (more functions)
// TEST
console.log(runUrl('/cars'))
console.log(runUrl('/companies/f505ecfb74/cars/5e735f505c/projects'))
console.log(runUrl('/companies/f505ecfb74/room/5e735f505c'))
Here is my proposition, similar to tomer raitz idea but use regexp to detect parameters
function runUrl(url) {
let result = undefined;
let u = url.split("/");
routes.find( ([route,func]) => {
let r = route.split("/");
if(r.length==u.length && r.every( (el,i) => /^:/.test(el) || el===u[i] ) ){
let params = u.filter((el,i)=> /^:/.test(r[i]));
result = func.call(this,...params);
return true;
}
return false;
})
return result;
}
// -----------
// TEST
// -----------
let routes = [
['/cars', cars ],
['/companies/:companyId/cars/:carId/projects', projects ],
['/companies/:companyId/room/:roomId', rooms ],
//...
];
function cars() { return ["car1","car2"]; }
function projects(companyId,carId) { return [`proj-${companyId}`,`proj-${carId}`]; }
function rooms(companyId,roomId) { return `room-${companyId}-room-${roomId}`; }
// TEST
console.log(runUrl('/companies/f505ecfb74/cars/5e735f505c/projects'));
console.log(runUrl('/cars'))
console.log(runUrl('/companies/ABC123/room/DEF5678'))

Categories