Search code examples
javascriptdexie

How to run a function in an javascript object programatically?


Am trying to create a user query with Dexie where the user queries the database in their own but i cant get it to work.

<!-- html -->

<div class="window" style="padding-top: 1.5rem;">
<link rel="stylesheet" type="text/css" href="./css/bootstrap-grid.min.css">
 <div class="window-content">
   <div class="pane-group">
       <div class="pane" style="padding:4rem;padding-top: 0 ">
           <h3 class="text-center"><u><span class="icon icon icon-code icon-text" style="color:#4e5851;padding-right:1rem "></span>Advanced Queries</u></h3>
           <table class="table-striped mb-2">
               <thead>
               <tr>
                   <th colspan="3"><input class="form-control" type="" name="query" id="query"></th>
                   <th style="width:4rem"><button class="btn btn-default" id="run">
                       <span class="icon icon-search"></span>
                   </button></th>
               </tr>
           </thead>
           </table>
           <div class ="row" style="display: flex" id='display_body'>

           </div>
       </div>
   </div>
</div>
</div>

//script

document.querySelector('#run').addEventListener("click", function(){
const { init_data} = require('../res/reusable');
var db = init_data(Dexie);
let torun = document.querySelector('#query').value; 
let mangoArray=torun.split('.')
//console.log('mangoArray');
if (mangoArray.length== '1') {
    db[mangoArray[0]].each(item=>{
        console.log(item);
});

}else if(mangoArray.length== '2'){
db[mangoArray[0]][mongoArray[1]].each(item=>{
console.log(item);
});
}
});

When i input devices in input (a table in the dexie database it works) in full it should run db.devices.each

However i cant get functions to work inside the dexie class. so when i input devices.orderBy('name') i get undefined error

//error
Uncaught TypeError: Cannot read property 'each' of undefined

How do i achieve this?


Solution

  • First of all, the thing you try to do is quite dangerous; giving a user an ability to perform an arbitrary query on the database from the front-end of your app. I advise caution.

    Second of all - the error says it all - you cannot call a method each() on undefined. What is undefined then? See, when your query looks like this: devices.orderBy('name'), the code executes the following:

    let mangoArray=torun.split('.') // ["devices", "orderBy('name')"]
    ...
    }else if(mangoArray.length== '2'){
    db[mangoArray[0]][mongoArray[1]]
    // ^ now pay attention: db["devices"]["orderBy('name')"]
    .each(item=>{
      console.log(item);
    });
    

    So, while the db object has an attribute field devices, it certainly does not have orderBy('name'). If you want to call the method of this object, there are several ways to deal with this. The easiest (but the most dangerous) would be to skip the splitting and handle this with eval:

    const query = eval(`db.${torun}`)
    query.each(...)
    

    But this allows a user to do whatever he wants with your data - delete, modify, corrupt, etc. The more safe way would be to use some quite complex regex validation on the input.

    The safest, and most advised, would be to actually develop a user-friendly interface that allows the user to access your data with full control. Make some forms that let user choose which data he wants to get, how to order them, filter them, then send this data through a server and return adequate response. This is called "hiding implementation" - your app's user don't need to know which database you are using, let alone the API of this database!

    Hope this helps.