<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<textarea rows=5 style="width:100%" id="source" onChange="updateQuery(this.value)"></textarea>
<textarea rows=5 style="width:100%" id="result"></textarea>
</body>
</html>
//var re = /(?:SELECT\s+?([a-z][a-z0-9_,.()* ]*?)\s+){1}(?:FROM\s+([a-z_][a-z_$0-9@]+)\s+?){1}(?:JOIN\s+([a-z_][a-z_$0-9@]*?)\s+ON\s+([a-z][a-z0-9_,.]*?)\s+=\s+([a-z][a-z0-9_,.]*)\s+?)*(?:GROUP\sBY\s+?([a-z][a-z0-9_,.()*]+)\s*)?(?:ORDER\sBY\s+?([a-z][a-z0-9_,.]*)\s*?)?/i;
var query = 'SELECT bills.vendor.name, bills.person.first_name FROM bills JOIN persons ON bills.person=person.id JOIN vendors ON bills.vendor=vendors.id GROUP BY count(*) ORDER BY bill.id';
function updateQuery(query) {
console.log(query.match(re))
document.getElementById('result').value = new BuildMongoQuery(query)
}
document.getElementById('source').value = query
document.getElementById('result').value = new BuildMongoQuery(query);
function BuildMongoQuery(query) {
this.query = query;
this.tokens = [];
this.mongoQuery = [];
this.selects = {};
this.from = '';
var tokens = [
'SELECT',
'FROM',
'JOIN',
'WHERE',
'GROUP BY',
'ORDER BY'
]
this.build = function() {
if(!this.query)
return new Error('query is required');
this.parts = [];
this.parseSql();
//return this.addJoins().addSelect(this.parts[1]).From(this.parts[2]).addGroupBy(this.parts[3]).toString();
}
this.parseSql = function() {
var re = /[A-Za-z_.]+\(.*?\)+|\(.*?\)+|"(?:[^"]|\"|"")*"+|'[^'](?:|\'|'')*'+|`(?:[^`]|``)*`+|[^ ,]+|,/ig
this.tokens = this.query.match(re);
console.log("Tokens", this.tokens)
this.getSelectFromQuery();
var afterFromIndex = this.tokens.indexOf("FROM") +1;
var untilFromLength = (this.tokens.indexOf("JOIN") != -1 ? this.tokens.indexOf("JOIN") : this.tokens.indexOf("WHERE")) - afterFromIndex;
this.addFrom(this.tokens.splice(afterFromIndex, untilFromLength).pop())
var afterJoinIndex = this.tokens.indexOf("JOIN")+1;
var untilJoinLength = (this.tokens.indexOf("WHERE") != -1 ? this.tokens.indexOf("WHERE") : this.tokens.indexOf("GROUP")) - afterJoinIndex;
this.addJoins(this.tokens.splice(afterJoinIndex, untilJoinLength))
}
this.addGroupBy = function(group_by) {
// TODO: $group statement build
console.log("Group by: ", group_by)
return this;
}
this.getSelectFromQuery = function() {
var afterSelectIndex = this.tokens.indexOf("SELECT") +1;
var untilSelectsLength = this.tokens.indexOf("FROM") - afterSelectIndex;
this.addSelect(this.tokens.splice(afterSelectIndex, untilSelectsLength).filter(function(select){ return select != ","}));
}
this.addSelect = function(selected_attributes) {
this.selects = selected_attributes;
// TODO: $project statement build
console.log("Selected attributes: ", selected_attributes)
return this;
}
this.addFrom = function(from_table) {
console.log("From table: ", from_table)
this.from = from_table;
return this;
}
this.addWhere = function(where_query) {
this.selects = selected_attributes;
// TODO: $project statement build
console.log("Selected attributes: ", selected_attributes)
return this;
}
this.addJoins = function(joins) {
console.log("With joins: ", joins);
joins = joins.reduce(function(acc, item) {
if(item == "JOIN") {
acc.push([])
}
else {
if(item == "ON")
return acc;
var lastIdx = acc.length > 0 ? acc.length -1 : 0;
acc[lastIdx] = acc[lastIdx] || [];
acc[lastIdx].push(item)
}
return acc;
},[]).map((join)=>{
table_name = join[0];
attrs = join[1].split("=")
attrs = attrs.reduce((acc, attr) => {
if(this.from && attr.indexOf(this.from) != -1)
acc.localField= attr.split(".").pop();
else
acc.foreignField= attr.split(".").pop();
return acc;
},{})
this.mongoQuery.push({
$lookup: {
"from" : table_name,
"localField" : attrs.localField,
"foreignField" : attrs.foreignField,
"as" : attrs.localField
}
})
this.mongoQuery.push( {
$unwind: "$"+attrs.localField
});
})
return this;
}
function getLastIndexBeforeNextToken(currentIndex) {
}
this.toString = function() {
return "db.getCollection('"+this.from+"').aggregate(\n"+JSON.stringify(this.mongoQuery,null, 2)+"\n);"
}
return this.build();
}
Output
This bin was created anonymously and its free preview time has expired (learn why). — Get a free unrestricted account
Dismiss xKeyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |