Last active
January 16, 2018 21:56
-
-
Save davidbalbert/50272b7e88d80a9a41f6ca0ad55cbcc7 to your computer and use it in GitHub Desktop.
Database.js
This file contains 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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Database.js</title> | |
</head> | |
<body> | |
<script> | |
'use strict'; | |
function isVar(x) { | |
return typeof x === 'string' && x[0] === '$'; | |
} | |
const EMPTY_BINDING = {facts: []}; | |
class Database { | |
constructor(...facts) { | |
this.facts = new Set(facts); | |
} | |
assert(fact) { | |
this.facts.add(fact); | |
} | |
refute(fact) { | |
this.facts.delete(fact); | |
} | |
query(qs, callback, bindings = [EMPTY_BINDING]) { | |
if (qs.length === 0) { | |
bindings.forEach(b => { | |
const assert = (fact) => { | |
fact.provenance = b.facts; | |
this.assert(fact); | |
} | |
const refute = (fact) => this.refute(fact); | |
callback(b, assert, refute) | |
}); | |
return; | |
} | |
const newBindings = this.match(qs[0], this.facts, bindings); | |
return this.query(qs.slice(1), callback, newBindings); | |
} | |
match(q, facts, bindings) { | |
let filtered = []; | |
for (let b of bindings) { | |
for (let f of facts) { | |
const newB = this.matchOne(q, f, b); | |
if (newB) { | |
filtered.push(newB); | |
} | |
} | |
} | |
return filtered; | |
} | |
matchOne(q, fact, binding) { | |
if (q.length !== fact.length) { | |
return null; | |
} | |
let newB = {...binding, facts: [...binding.facts, fact]}; | |
for (let i in q) { | |
const qpart = q[i]; | |
if (isVar(qpart) && newB.hasOwnProperty(qpart) && newB[qpart] !== fact[i]) { | |
return null; | |
} else if (isVar(qpart)) { | |
newB[qpart] = fact[i]; | |
} else if (qpart !== fact[i]) { | |
return null; | |
} | |
} | |
return newB; | |
} | |
} | |
let db = new Database( | |
['C1', 'is a', 'circle', 'at', '(', 300, ',', 300, ')'], | |
['C1', '\'s', 'color', 'is', 'blue'], | |
['C1', '\'s', 'radius', 'is', 50], | |
['C2', 'is a', 'circle', 'at', '(', 200, ',', 500, ')'], | |
['C2', '\'s', 'color', 'is', 'red'], | |
['C2', '\'s', 'radius', 'is', 120], | |
) | |
db.query([ | |
['$name', 'is a', 'circle', 'at', '(', '$x', ',', '$y', ')'], | |
['$name', '\'s', 'radius', 'is', '$r'], | |
['$name', '\'s', 'color', 'is', 'red'], | |
], m => console.log(m)); | |
db.query([ | |
['$name', 'is a', 'circle', 'at', '(', '$x', ',', '$y', ')'], | |
['$name', '\'s', 'radius', 'is', '$r'], | |
], ({$name, $r}, assert, refute) => { | |
console.log($name, $r); | |
if ($r > 100) { | |
assert([$name, 'is', 'large']); | |
} | |
}) | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment