Created
February 9, 2020 18:41
-
-
Save malexsan1/762115fb3d33441657101ae8956d414a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var movieDatabase = { | |
movie: [ | |
{ id: 1, name: 'Avatar', directorID: 1 }, | |
{ id: 2, name: 'Titanic', directorID: 1 }, | |
{ id: 3, name: 'Infamous', directorID: 2 }, | |
{ id: 4, name: 'Skyfall', directorID: 3 }, | |
{ id: 5, name: 'Aliens', directorID: 1 }, | |
], | |
actor: [ | |
{ id: 1, name: 'Leonardo DiCaprio' }, | |
{ id: 2, name: 'Sigourney Weaver' }, | |
{ id: 3, name: 'Daniel Craig' }, | |
], | |
director: [ | |
{ id: 1, name: 'James Cameron' }, | |
{ id: 2, name: 'Douglas McGrath' }, | |
{ id: 3, name: 'Sam Mendes' }, | |
], | |
actor_to_movie: [ | |
{ movieID: 1, actorID: 2 }, | |
{ movieID: 2, actorID: 1 }, | |
{ movieID: 3, actorID: 2 }, | |
{ movieID: 3, actorID: 3 }, | |
{ movieID: 4, actorID: 3 }, | |
{ movieID: 5, actorID: 2 }, | |
], | |
}; | |
/** | |
* operators = SELECT | FROM | WHERE | JOIN | |
* | |
*/ | |
const SQLOp = Symbol('sql_operation'); | |
const SQLValue = Symbol('sql_value'); | |
const SELECT_Op = Symbol('SELECT'); | |
const FROM_Op = Symbol('FROM'); | |
const ON_Op = Symbol('ON'); | |
const WHERE_Op = Symbol('WHERE'); | |
const JOIN_Op = Symbol('JOIN'); | |
const operations = { | |
select: SELECT_Op, | |
SELECT: SELECT_Op, | |
from: FROM_Op, | |
FROM: FROM_Op, | |
on: ON_Op, | |
ON: ON_Op, | |
where: WHERE_Op, | |
WHERE: WHERE_Op, | |
join: JOIN_Op, | |
JOIN: JOIN_Op, | |
}; | |
function SQLEngine(database) { | |
this.database = database; | |
this.parseQuery = function(query) { | |
const tokens = query.split(' '); | |
let AST = []; | |
let c = 0; | |
const peek = () => tokens[c]; | |
const consume = () => tokens[c++]; | |
const sqlOperations = Object.keys(operations); | |
const parseOperation = () => { | |
const value = consume().toLowerCase(); | |
const node = { val: value, type: operations[value], values: [] }; | |
while (peek() && !sqlOperations.includes(peek())) { | |
if (operations[value] === WHERE_Op || operations[value] === ON_Op) { | |
node.values.push(...parseTestValues()); | |
} else { | |
node.values.push(parseValue()); | |
} | |
} | |
return node; | |
}; | |
const parseValue = () => { | |
return consume().replace(',', ''); | |
}; | |
const parseTestValues = () => { | |
const firstOperand = consume(); | |
const comparison = consume(); | |
let secondOperand = ''; | |
while (peek() && !sqlOperations.includes(peek())) { | |
secondOperand += `${consume()} `; | |
} | |
return [firstOperand, comparison, secondOperand.trim().replace("'", '')]; | |
}; | |
const parseExpr = () => { | |
while (peek()) { | |
AST.push(parseOperation()); | |
} | |
}; | |
parseExpr(); | |
return AST; | |
}; | |
this.evalFROM = function(queries = []) { | |
const fromQueries = queries.filter(q => q.type === FROM_Op); | |
console.log(fromQueries); | |
}; | |
this.evalSELECT = function(queries = []) { | |
const result = []; | |
const { values } = queries.find(q => q.type === SELECT_Op); | |
const whereQuerie = queries.find(q => q.type === WHERE_Op); | |
const selectObj = values.reduce((acc, v) => { | |
const [table, column] = v.split('.'); | |
if (acc[table]) { | |
acc[table].push(column); | |
} else { | |
acc[table] = [column]; | |
} | |
return acc; | |
}, {}); | |
Object.entries(selectObj).forEach(([table, columns]) => { | |
result.push( | |
...this.database[table].map(row => | |
columns.reduce( | |
(acc, c) => ({ | |
...acc, | |
[c]: row[c], | |
}), | |
{}, | |
), | |
), | |
); | |
}); | |
}; | |
this.execute = function(query) { | |
const queries = this.parseQuery(query); | |
this.evalSELECT(queries); | |
}; | |
} | |
var engine = new SQLEngine(movieDatabase); | |
engine.execute('SELECT movie.name FROM movie WHERE movie.directorID = 1'); | |
// engine.execute( | |
// 'SELECT movie.name, actor.name ' + | |
// 'FROM movie ' + | |
// 'JOIN actor_to_movie ON actor_to_movie.movieID = movie.id ' + | |
// 'JOIN actor ON actor_to_movie.actorID = actor.id ' + | |
// "WHERE actor.name <> 'Daniel Craig'", | |
// ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment