C2FO / patio

Idiomatic database toolkit

Home Page:http://c2fo.github.io/patio

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Serial queries

opened this issue · comments

Hi, is not an issue, is much more a request for assistance. I've 8 queries, but they can't be done async. I want to execute them in series and after use all dataset (8) results, how can I achieve that ?

I've also this query, and I want to translate it in patio

select `SADate`, sum(`SAUnits`) as total from Sales WHERE `SAApplicationSku`='210886' and `SATypeIdentifier` in ('1','1T','1F','F1','IA1') and `SAUnits`<0 group by `SADate` order by `SADate` desc

Thank you for your help.

Try comb.serial: http://c2fo.github.com/comb/comb.html#.serial

On Wed, Oct 17, 2012 at 10:12 AM, Ismael Gorissen
notifications@github.comwrote:

Hi, is not an issue, is much more a request for assistance. I've 8
queries, but they can't be done async. I want to execute them in series,
how can I achieve that ?

Thank you for your help.


Reply to this email directly or view it on GitHubhttps://github.com//issues/54.

I saw that.

var asyncAction = function(item, timeout){                                
   var ret = new comb.Promise(); 
   //bind the callback to the promise ignoring any other arguments passed in                                      
   setTimeout(ret.callback.bind(ret, item), timeout);
   return ret.promise();                                                            
};                                                                        
comb.serial([   
    //comb.partial returns a function that will execute asyncAction with the specified arguments
    comb.partial(asyncAction, 1, 1000),                                       
    comb.partial(asyncAction, 2, 900),                                  
    comb.partial(asyncAction, 3, 800),                                    
    comb.partial(asyncAction, 4, 700),                                    
    comb.partial(asyncAction, 5, 600),                                    
    comb.partial(asyncAction, 6, 500)                                     
]).then(function(results){                                                
    console.log(results); // [1,2,3,4,5,6];                               
});

In this example the results variable is an array of each query result ?

Yep that would be be right.

So there are a couple of options.

comb.chain

comb.chain allows you to execute items serially and pipes the results from one item to the next.

comb.chain([
    function queryOne(){
        return db.from("myTable").filter({a : 1}).all();
    },
    function  queryTwo(resultsFromQueryOne){
         //do something with results and return the promise from the next query
    },
    //etc etc.
    function queryEight(resultsFromQuerySeven){
    }
]).chain(function(resultsFromQueryEight){
    //all queries are done
});

comb.serial

comb.serial is similar to comb.chain except that it does not pipe results from one function to the next, instead it will buffer the results up till the end.

comb.Promise#chain

I find I use this method the most, but you can use the chain method from each promise for the flow control also.

var ds = db.from("myTable");
ds.filter({a : 1}).all()
   .chain(function(results){
       return ds.filter(/*do some intersting filter*/).one();
   })
   .chain(function(resultsTwo){
      return ds.filter(/*do some intersting filter*/).one();
   });

Hope this helps

Thank you. I will try this now.

Another question.
I have this query

select `SADate`, sum(`SAUnits`) as total from Sales WHERE `SAApplicationSku`='210886' and `SATypeIdentifier` in ('1','1T','1F','F1','IA1') and `SAUnits`<0 group by `SADate` order by `SADate` desc

in patio it wil be ?

Yep NP,

As for the query if you are using a model for Sales and you expect a model back then you could do something like this.

var sql = patio.sql,
     //sum is not actually defined but patio uses proxies to allow you to define any function or identifier you want.
      sum = sql.sum;
Sales
    //select `SADate`, sum(`SAUnits`) as total
   .select("SADate", sum("SAUnits").as("total"))
   .filter({
      //`SAApplicationSku`='210886'
      SAApplicationSku : 210886, 
      //`SATypeIdentifier` in ('1','1T','1F','F1','IA1')
      SATypeIdentifier : ['1','1T','1F','F1','IA1'],
      //`SAUnits`<0
      SAUnits : {lt : 0}
   })
   //group by `SADate`
   .group("SADate")
    //order by `SADate` desc, notice as mentioned above sql can be used to define identifiers also
   .order(sql.SADate.desc());

If you are not using models and just the database and datasets

var sql = patio.sql,
     //sum is not actually defined but patio uses proxies to allow you to define any function or identifier you want.
      sum = sql.sum;
db.from("Sales")
    //select `SADate`, sum(`SAUnits`) as total
   .select("SADate", sum("SAUnits").as("total"))
   .filter({
      //`SAApplicationSku`='210886'
      SAApplicationSku : 210886, 
      //`SATypeIdentifier` in ('1','1T','1F','F1','IA1')
      SATypeIdentifier : ['1','1T','1F','F1','IA1'],
      //`SAUnits`<0
      SAUnits : {lt : 0}
   })
   //group by `SADate`
   .group("SADate")
   //order by `SADate` desc, notice as mentioned above sql can be used to define identifiers also
   .order(sql.SADate.desc());

-Doug

Nice it works perfectly !!!

Thank you (Doug and mbenedettini)

Hi, sorry for reopened this issue but, again, I need your help !!

I need to do multiple things synchronously.
I have a table Application, I make a request to retrieve some applications information with some filters, then for each application in this array, I need to retrieve all countries where I can found this application. When all of this are done, I must create a object that contains each applications with all informations like this.

[
 {
  idApp: ...,
  skuApp: ...,
  countries: [ ... ]
 },
 ...
]

So, I must do a thing like this (but it not works)

comb.chain([
 function()
 {
  // retrieve all applications
 },
 function(apps)
 {
  // create results object

  // forEach(apps) need to retrieve countries and populate the results object

  // return results
 }
]).then(function(results)
{
 // results is the object talk earlier
});

How can I achieve this ?

Thank you

I hav actually this

DB.fetch("SELECT APBundleId, APSku, APItunesId FROM Application WHERE APSku IS NOT NULL AND APItunesId IS NOT NULL")
        .all()
        .then(function(apps)
        {
            if (apps) {
                console.log(_NOTICE("NOTICE Review") + " : One or more applications found");
                //console.log(apps);
                for (var i=0; i<apps.length; i++) {
                    console.log(apps[i]);
                    DB.fetch("SELECT SACountryCode FROM Application JOIN Sales ON APSku=SAApplicationSKu WHERE APSku=? AND APItunesId=? GROUP BY SACountryCode ORDER BY SACountryCode ASC", apps[i].APSku, apps[i].APItunesId)
                        .all()
                        .then(function(countries)
                        {
                            if (countries) {
                                console.log(_NOTICE("NOTICE Review") + " : One or more countries found");
                                console.log(countries);

                            } else {
                                console.log(_WARNING("WARNING Review") + " : No country found");
                            }
                        }, errorHandler);
                }
            } else {
                console.log(_WARNING("WARNING Review") + " : No application found");
            }
        }, errorHandler);

If you have also a book name which explain asynchronous javascript !!

Using comb.chain

chain([
        function()
        {
            return DB.fetch("SELECT APItunesId, SACountryCode FROM Application JOIN Sales ON APSku=SAApplicationSKu WHERE APSku IS NOT NULL AND APItunesId IS NOT NULL").all()
        },
        function(apps)
        {
            var apps_countries = [];
            var found;
            for (var i=0; i<apps.length; i++) {
                found = false;

                if (apps_countries.length > 0) {
                    for (var j=0; j<apps_countries.length; j++) {
                        if (apps[i].APItunesId == apps_countries[j].id) {
                            found = true;
                            apps_countries[j].countries.push(apps[i].SACountryCode);
                            break;
                        }
                    }

                    if (!found) {
                        var app = {
                            id: apps[i].APItunesId,
                            countries: [apps[i].SACountryCode]
                        };
                        apps_countries.push(app);
                    }
                } else {
                    var app = {
                        id: apps[i].APItunesId,
                        countries: [apps[i].SACountryCode]
                    };
                    apps_countries.push(app);
                }
            }

            return apps_countries;
        }
    ]).then(function(results)
    {
        console.log(results);
    }, errorHandler);

It gave me good data but it's not what I want !!

Hi im sure I exactly understand what you are trying to get but does this work?

DB.fetch("SELECT APBundleId, APSku, APItunesId FROM Application WHERE APSku IS NOT NULL AND APItunesId IS NOT NULL")
    .map(function(app){
       return DB
           .fetch("SELECT SACountryCode FROM Application JOIN Sales ON APSku=SAApplicationSKu WHERE APSku=? AND APItunesId=? GROUP BY SACountryCode ORDER BY SACountryCode ASC", app.APSku, app.APItunesId)
           .map(function(country){
                return country.SACountryCode;
            })
            .chain(function (countries) {
                return {
                    idApp : app.APItunesId,
                    skuApp : app.APSku,
                    countries : countries
                };
            });
    })
    .then(function (apps) {
        if (apps) {
            console.log(_NOTICE("NOTICE Review") + " : One or more applications found");
            //console.log(apps);
            for (var i = 0; i < apps.length; i++) {
                console.log(apps[i]);

            }
        } else {
            console.log(_WARNING("WARNING Review") + " : No application found");
        }
    }, errorHandler);

Wow It works perfectly !! Can you explain what you have done there, please ?

Hi,

So what I did is leverage the map action method which works very similarly to the Array#map method in javascript the one difference is that you can return a promise from your iterator function.

So in this case I return another promise that runs the query and plucks the country code and then returns the object in which you were wanting to get.

One nice thing about working with patio is that all of the iteration methods (forEach, map, etc...) will accept a promise as the return value. If a promise is received then the iteration will wait for it to complete before resolving.

-Doug