Javascript LINQ-like Querying?

Just coding for coding sake, I decided to try implement a LINQ-like query in JavaScript.  And the result is as follow:

/*
 *
 * Javascript LINQ-like query proof of concept 
 * Jimmy Chandra - 16 July 2007 
 */
 
/* 
 * Quicksort implementation for JavaScript Array (based on  
 * http://en.literateprograms.org/Quicksort_(JavaScript)), 
 * modified to pass a function delegate for the comparison function. 
 */
 
Array.prototype.swap = function(i, j) {
    var a = this,
        t = a[i];
    a[i] = a[j];
    a[j] = t;
}
 
function partition(a, s, e, p, l) {
    var v = a[p],
        t = s,
        i;
    
    a.swap(p, e - 1);
    
    for (i = s; i < e - 1; i++) {
        if (l(a[i], v)) {
            a.swap(t, i);
            t++;
        }
    }
    
    a.swap(e - 1, t);
    
    return t;
}
 
function qsort(a, s, e, l) {
    var p;
    if (e - 1 > s) {
        p = s + Math.floor((e - s) / 2);
        p = partition(a, s, e, p, l);
        
        qsort(a, s, p, l);
        qsort(a, p + 1, e, l);
    }
}
 
Array.prototype.quicksort = function (l) {
    qsort(this, 0, this.length, l);
}
 
 
/*
 * JavaScript LINQ-like query engine sample implementation 
 */
 
function _each(o, l, a) {
    var r = [],
        m = o.length,
        i;
        
    if (l) {
        for (i = 0; i < m; i++) {
            if (l(o[i])) {
                a(r, o, i);
            }
        }
    } else {
        for (i = 0; i < m; i++) {
            a(r, o, i);
        }
    }
    return r;
}
 
function from(o) {
    return new _from(o);
}
 
function _from(o) {
    this.items = o;
}
 
_from.prototype.where = function(l) {
    return new _where(
        _each(this.items, l, 
            function(r, o, i) {
                r.push(o[i]);
            }));
}
 
function _select(l) {
    return _each(this.items, l, 
        function(r, o, i) {
            r.push(l(o[i]));
        });
}
 
_from.prototype.select = _select;
 
function _where(o) {
    this.items = o;
}
 
_where.prototype.select = _select;
 
_where.prototype.orderby = function(a) {
    var f,
        k = a.length,
        r = _each(this.items, null,
            function(r, o, i) {
                r.push(o[i]);
            });
            
    if (k === 1 && a[0] === "") {
        f = function(i, j) { 
                return i <= j; 
            };
    } else {
        f = function(i, j) {
                var l = "",
                    r = "";
                    
                for (var n = 0; n < k; n++) {
                    l += i[a[n]];
                    r += j[a[n]];
                }
                
                return l <= r;
            };
    }
    
    r.quicksort(f);
    
    return new _orderby(r);
}
 
function _orderby(o) {
    this.items = o;
}
 
_orderby.prototype.select = _select;
 
/*
 * Javascript LINQ-like querying example 
 */
 
var numbers = [17, 6, 12, 14, 20, 13, 10];
var b = from (numbers).
        where (function(n) { return n > 9 && n < 20; }).
        orderby ([ "" ]).
        select (function(n) { return n; });
        
for (var x = 0, l = b.length; x < l; x++) {
    WScript.Echo(b[x]);
}
 
var peoples = [
    { FirstName : "John", LastName : "Doe", Age : 29 },
    { FirstName : "Jane", LastName : "Doe", Age : 33 },
    { FirstName : "Mary", LastName : "White", Age : 31 },
    { FirstName : "Barry", LastName : "White", Age : 31 },
    { FirstName : "Kevin", LastName : "Black", Age : 31 },
    { FirstName : "Anna", LastName : "Smith", Age : 1 }];
    
var p = from (peoples).
        where (function(n) { return n.LastName === "Doe" || n.LastName === "White"; }).
        orderby([ "Age", "LastName", "FirstName" ]).
        select(function(n) { return { FullName : n.FirstName + " " + n.LastName, Age : n.Age }; });
        
for (var x = 0, l = p.length; x < l; x++) {
    WScript.Echo(p[x].FullName + ":" + p[x].Age);
}

To test it, cut and paste the code into a text file, name it whatever you want with .js extension and run it from command prompt by typing cscript the_filename_here.js.  Fun :)

Share this post: | | | |
Published Monday, July 16, 2007 6:38 PM by Jimmy Chandra
Filed under:

Comments

# re: Javascript LINQ???

Interesting, but then remember that C# LINQ is all about language keywords, not just functions or API. It is more than just functions/API, even though the keywords translate into API. In order to create JLINQ, one must touch the JScript compiler/interpreter.

Another thing, from the usage example:

from (numbers).

where (function(n) { return n > 9 && n < 20; }).

select (function(n) { return n; });

The "(function(n) { return n > 9 && n < 20; })" and "(function(n) { return n; })" are still functions (Anonymous Delegate). Not yet an expression (Lambda Expression). It is still has the keyword "return".

It should have been something like:

from (n in numbers).

where (n>9 && n<20).

select (n);

Ain't JavaScript capable of Lambda Expressions like this? You know, Functional Programming capability? C# 3.0 has Lambda Expression, it begins to be Functional too. :)

Tuesday, July 17, 2007 12:08 PM by norman

# re: Javascript LINQ???

cahnom,

Sorry, CS must have inserted smileys automatically.

It's fixed now.

norman,

Agreed, to implement LINQ fully, you would have to touch the compiler / interpreter.  However, this is not an attempt to fully implement LINQ, perhaps the title was a bit misleading.  What I was trying to achieve is emulate LINQ-like querying syntax on top of the current JavaScript language.

Again, I agreed, to achieve .NET 3.5 lambda expression you would have to touch the compiler / interpreter.  I am just using the term "lambda" interchangably with "function delegate" freely here.  To me, at least, technically, lambda behind the scene is really function delegate that is expressed in a more compact syntax.

AFAIK, JavaScript does not currently support the lambda expression syntax ((x,y) => x > y).  So I have to make due with the function delegate syntax function(x,y) { return x > y; } which work just as nicely.  :)

I am pretty happy on the result so far.

Tuesday, July 17, 2007 12:26 PM by Jimmy Chandra

# re: Javascript LINQ-like Querying?

Changed the post title and some of the comments in the code to avoid further "confusion".

Tuesday, July 17, 2007 12:35 PM by Jimmy Chandra