0

First, I'm just getting started with node js (look at the question), so please bear with me

This is a case I made to make my question clearer. I made a function to be called on another JS :

exports.test = function(req, res){
  connection.query('SELECT * FROM `test`', function (error, results) {
  console.log(results);
  });
};

Then I can call it with object.test();

I want to generalize this function, by passing the table name from another JS, instead of hardcoding it. How to do that?

In Java, I could googling about this easily. However, on Node, almost all search results telling about the parameter in the url (POST/GET), but my need is to just passing a param/args to a function.

Thanks in advance

Blaze Tama
  • 10,828
  • 13
  • 69
  • 129
  • 1
    Why don't you just pass it in the function's arguments, like `object.test(req, res, tableName)` ? – Jeremy Thille Aug 24 '17 at 09:56
  • @JeremyThille: He/she probably wants to use the result with Express-style middleware, which will call the function with `req, res`. – T.J. Crowder Aug 24 '17 at 09:58
  • They can attach the tablename to `req` then. `req.tableName="test"` – Jeremy Thille Aug 24 '17 at 10:00
  • @JeremyThille: Those come from Express, not the OP's code. It would be possible to insert *another* middleware function that added properties to `req`, but I wouldn't consider it good design, not least because of potential conflict. Building a function with baked-in info like this is entirely standard practice. – T.J. Crowder Aug 24 '17 at 10:03

3 Answers3

3

This isn't really a Node question, it's a JavaScript question.

You can create a function that returns a function. You pass the table name to the builder, and then use it in the function that builder creates:

exports.makeTest = function(tableName) {
  return function test(req, res){
    connection.query('SELECT * FROM `' + tableName + '`', function (error, results) {
      console.log(results);
    });
  };
};

Note: I assume tableName comes from code you control and can trust; otherwise, string concatenation is not acceptable in the above.

You'd use it like this:

var test = makeTest("test");

...and then call test with req and res (or more likely, pass it to something like Express that will).

Here's a non-Node example just to show how the parts work:

function makeTest(tableName) {
  return function test(req, res) {
    console.log("Table name is:", tableName);
    console.log("req is:", req);
    console.log("res is:", res);
  };
}

var test = makeTest("test");
console.log("Call 1:");
test({name: "req1"}, {name: "res1"});
console.log("Call 2:");
test({name: "req2"}, {name: "res2"});
.as-console-wrapper {
  max-height: 100% !important;
}

It may seem surprising that the tableName argument is still accessible to the test function after makeTest returns. That's the nature of JavaScript's closures. You can read more about closures here:

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    Very interesting, I will reuse that in future developments. – Jeremy Thille Aug 24 '17 at 10:06
  • Could you please explain `or more likely, pass it to something like Express that will`? I don't really get how to "pass it to Express" – Jeremy Thille Aug 25 '17 at 08:12
  • @JeremyThille: Express has you call functions to register handlers for routes in your web server ([example here](http://expressjs.com/en/starter/hello-world.html)): After defining your "app" (an HTTP server listening on a given address and port), you call (for instance) `get` to set up a handler for GET requests. For instance, the root route: `app.get("/", ...)`. That's what you pass the function to: `app.get("/", test)`. Then Express calls that function when a request for that route is received, passing it the `req` (request) and `res` (response) objects. – T.J. Crowder Aug 25 '17 at 08:16
  • *(cont'd)* There I've used `test` (the variable created in my answer), but more likely in this case you'd just pass the result of calling `makeTest("test")` (the function it creates) directly into `get`: `app.get("/", makeTest("test"))`. Now, I'm just guessing based on the `(req, res)` parameter list that the OP is using Express; they may well not be, but they're likely to be using *something* where they pass the function to it and it, rather than their own code, calls the function with a set argument list. – T.J. Crowder Aug 25 '17 at 08:21
  • Interesting, I think I'm getting it. But how to pass a variable to `makeTest`, instead of `"test"`? Where would this variable come from? Edit : I think it could be from the route : `app.get("/:tableName", makeTest(req.params.tableName))`, right? Makes sense. – Jeremy Thille Aug 25 '17 at 08:24
  • @JeremyThille: You'd pass it just like passing any other variable to a function; its *value* (not the variable) would be passed. It could come from any scope accessible where the `makeTest(...)` call is (e.g., the current scope, or any containing scope). – T.J. Crowder Aug 25 '17 at 08:28
  • Yep I got that, I was just wondering how to pass the variable to the router. Previous comment edited. Thanks, that helped :) – Jeremy Thille Aug 25 '17 at 08:29
  • @JeremyThille: No, in your `app.get("/:tableName", makeTest(req.params.tableName))` example, `makeTest` is called **before** `app.get` is called (think `foo(bar())`, it's exactly the same), and *long* before Express calls the handler in response to a GET. You access route parameters **inside** the handler (the function `makeTest` *returns*), via the `req.params` object passed to it ([example](http://expressjs.com/en/4x/api.html#req)). – T.J. Crowder Aug 25 '17 at 08:34
  • Ah right, if I go `makeTest(req.params.tableName)`, I may get `req is undefined` or something. Uuuuuuh I'll give this some thought. – Jeremy Thille Aug 25 '17 at 08:39
  • @JeremyThille: You'd get an error because `req` is an undeclared identifier in that scope. :-) Yeah, if you're interested in Express, play around with it a bit and you'll get it. – T.J. Crowder Aug 25 '17 at 08:45
  • 1
    To my shame, I must confess that I've been using Express and its router for a long while, and I only use Node and Express for my apps's back-end. But I never thought about this function-builder function and how to call it, I'll try and get better at it. – Jeremy Thille Aug 25 '17 at 08:57
1

you can use the concept of Higher order function in this

module.exports = function(tableName) {
  return function(req, res) {
    //...here you have tableName accessible
  };
};

And in the routes (if you're following the general flow of express app) where you are applying this controller,

const somethingController = require('/path/to/file');
route.get('/something', somethinController('test')); //...pass the table Name
Anshul Sahni
  • 626
  • 8
  • 21
0

So there are multiple points here.

Firstly, your test function takes two parameters - a req and a res. Assuming you're using express to create a HTTP server this symbolises the incoming request and the outbound response. So I would read up on how express attaches things like POST data or query parameters in order to allow you to pass dynamic data into a route handler.

Secondly, you can interpolate strings in Javascript with template literals. For instance:

`select * from ${myTableParameter}`
Alex Naish
  • 100
  • 6