Search code examples
javascriptknex.js

create object chaining using loop


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 :)


Solution

  • 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"])