Reputation: 162
Is there a way to create a chained object from loop? For example input:
["table1","table2","table3"]
output:
db
.select(fields)
.from(table)
.innerJoin("table1")
.innerJoin("table2")
.innerJoin("table3")
another input:
["table1","table2","table3","table4","table5"]
output:
db
.select(fields)
.from(table)
.innerJoin("table1")
.innerJoin("table2")
.innerJoin("table3")
.innerJoin("table4")
.innerJoin("table5")
Right now i have no idea how to do that except using eval, which isn't something i would like to do.
I need this to join multiple tables using knex, so if there any other way to do so, i will be really happy :)
Upvotes: 2
Views: 428
Reputation: 92460
The way chaining works is that each of those methods returns an object that has the next method as a property. This means you can use something like reduce()
to keep calling the next method on the object returned from the previous.
reduce()
accepts an initial object, which you can pass to get things rolling. Something like:
var tables = ["table1","table2","table3"]
let res = tables.reduce((res, table) => res.innerJoin(table), db.select(fields).from(table))
To get a sense how this works we can create a fake db
object with all the methods that return the object for the next method in the chain. The innerJoin
method just adds the argument to the value property:
// fake db object with these methods
const db = {
select(t) {
this.val = [] // initialize val
return this
},
from(t) {
return this
},
innerJoin(name) {
this.val.push("Added: " + name)
return this
}
}
var tables = ["table1","table2","table3"]
// call innerjoin for each of the tables
// this is the same as chaining them
let res = tables.reduce((res, table) => res.innerJoin(table), db.select().from())
// values where accumlated in the val property
console.log(res.val)
Upvotes: 3
Reputation: 3452
I think looking into functional programming will help you here.
I used a pipe function from the internet link below but you could use lodash/Ramda/underscore or whatever your fav util library is.
the two main concepts I'm using here is currying and piping.
What is 'Currying'? Currying is when you break down a function that takes multiple arguments into a series of functions that take part of the arguments we are also making use of curring which is returning a function from another function to compose new functions.
https://medium.com/@venomnert/pipe-function-in-javascript-8a22097a538e A pipe function takes an n sequence of operations; in which each operation takes an argument; process it; and gives the processed output as an input for the next operation in the sequence. The result of a pipe function is a function that is a bundled up version of the sequence of operations.
what we're doing here is taking an array, creating a new array of functions we want to apply to a value.
So we want to do a load of joins on a db.
join => con => con.innerJoin(join);
is taking a value i.e "table1" and returning a function that takes a db connection which calls the join and returns for the next one.
const joins = toJoin.map(join => con => con.innerJoin(join));
and this creates are array of functions to pass to pipe.
const db = ({
select: function (field) {
console.log('select', field)
return db
},
from: function (table) {
console.log('from', table)
return db;
},
innerJoin: function (join) {
console.log('innerJoin', join)
return db;
}
});
const _pipe = (a, b) => (arg) => b(a(arg));
const pipe = (args) => [].slice.apply(args).reduce(_pipe);
function joinInnerMultiple(table, fields, toJoin) {
const joins = toJoin.map(join => con => con.innerJoin(join));
return pipe(joins)(db.select(fields).from(table));
}
joinInnerMultiple("User", "uuid", ["table1", "table2", "table3", "table4", "table5"])
Upvotes: 0