;; lib/minikanren/tests/rdb.sx — relational database queries. ;; ;; Demonstrates how miniKanren can serve as a Datalog-style query engine ;; over fact tables. Tables are SX lists of tuples; the relation just ;; wraps `membero` over the table. (define rdb-employees (list (list "alice" "engineering" 100000) (list "bob" "marketing" 80000) (list "carol" "engineering" 90000) (list "dave" "engineering" 85000) (list "eve" "sales" 75000))) (define rdb-projects (list (list "alice" "compiler") (list "carol" "compiler") (list "dave" "runtime") (list "alice" "runtime") (list "eve" "outreach"))) ;; Relation views over the tables. (define employees (fn (name dept salary) (membero (list name dept salary) rdb-employees))) (define on-project (fn (name project) (membero (list name project) rdb-projects))) ;; --- queries --- (mk-test "rdb-engineering-staff" (let ((res (run* q (fresh (n s) (employees n "engineering" s) (== q n))))) (and (= (len res) 3) (and (some (fn (n) (= n "alice")) res) (and (some (fn (n) (= n "carol")) res) (some (fn (n) (= n "dave")) res))))) true) (mk-test "rdb-high-salary" (let ((res (run* q (fresh (n d s) (employees n d s) (lto-i 85000 s) (== q (list n s)))))) (and (= (len res) 2) (and (some (fn (r) (= r (list "alice" 100000))) res) (some (fn (r) (= r (list "carol" 90000))) res)))) true) (mk-test "rdb-join-employee-project" (let ((res (run* q (fresh (n d s) (employees n d s) (on-project n "compiler") (== q n))))) (and (= (len res) 2) (and (some (fn (n) (= n "alice")) res) (some (fn (n) (= n "carol")) res)))) true) (mk-test "rdb-engineers-on-runtime" (let ((res (run* q (fresh (n s) (employees n "engineering" s) (on-project n "runtime") (== q n))))) (and (= (len res) 2) (and (some (fn (n) (= n "alice")) res) (some (fn (n) (= n "dave")) res)))) true) (mk-test "rdb-people-on-multiple-projects" (let ((res (run* q (fresh (n p1 p2) (on-project n p1) (on-project n p2) (nafc (== p1 p2)) (== q n))))) (some (fn (n) (= n "alice")) res)) true) (mk-tests-run!)