Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 41s
New lib/datalog/demo.sx with three Datalog-as-query-language demos
over synthetic rose-ash data:
Federation: (mutual A B), (reachable A B), (foaf A C) over a
follows graph.
Content: (post-likes P N) via count aggregation, (popular P)
for likes >= 3, (interesting Me P) joining follows
+ authored + popular.
Permissions: (in-group A G) over transitive subgroup chains,
(can-access A R).
10 tests run each program against in-memory EDB tuples loaded via
dl-program-data.
Wiring to PostgreSQL and exposing as a service endpoint (/internal
/datalog) is out of scope for this loop — both would require
edits outside lib/datalog/. Programs above document the EDB shape
a real loader would populate.
203 lines
5.7 KiB
Plaintext
203 lines
5.7 KiB
Plaintext
;; lib/datalog/tests/demo.sx — Phase 10 demo programs.
|
|
|
|
(define dl-demo-pass 0)
|
|
(define dl-demo-fail 0)
|
|
(define dl-demo-failures (list))
|
|
|
|
(define
|
|
dl-demo-deep=?
|
|
(fn
|
|
(a b)
|
|
(cond
|
|
((and (list? a) (list? b))
|
|
(and (= (len a) (len b)) (dl-demo-deq-l? a b 0)))
|
|
((and (dict? a) (dict? b))
|
|
(let ((ka (keys a)) (kb (keys b)))
|
|
(and (= (len ka) (len kb)) (dl-demo-deq-d? a b ka 0))))
|
|
((and (number? a) (number? b)) (= a b))
|
|
(else (equal? a b)))))
|
|
|
|
(define
|
|
dl-demo-deq-l?
|
|
(fn
|
|
(a b i)
|
|
(cond
|
|
((>= i (len a)) true)
|
|
((not (dl-demo-deep=? (nth a i) (nth b i))) false)
|
|
(else (dl-demo-deq-l? a b (+ i 1))))))
|
|
|
|
(define
|
|
dl-demo-deq-d?
|
|
(fn
|
|
(a b ka i)
|
|
(cond
|
|
((>= i (len ka)) true)
|
|
((let ((k (nth ka i)))
|
|
(not (dl-demo-deep=? (get a k) (get b k))))
|
|
false)
|
|
(else (dl-demo-deq-d? a b ka (+ i 1))))))
|
|
|
|
(define
|
|
dl-demo-set=?
|
|
(fn
|
|
(a b)
|
|
(and
|
|
(= (len a) (len b))
|
|
(dl-demo-subset? a b)
|
|
(dl-demo-subset? b a))))
|
|
|
|
(define
|
|
dl-demo-subset?
|
|
(fn
|
|
(xs ys)
|
|
(cond
|
|
((= (len xs) 0) true)
|
|
((not (dl-demo-contains? ys (first xs))) false)
|
|
(else (dl-demo-subset? (rest xs) ys)))))
|
|
|
|
(define
|
|
dl-demo-contains?
|
|
(fn
|
|
(xs target)
|
|
(cond
|
|
((= (len xs) 0) false)
|
|
((dl-demo-deep=? (first xs) target) true)
|
|
(else (dl-demo-contains? (rest xs) target)))))
|
|
|
|
(define
|
|
dl-demo-test-set!
|
|
(fn
|
|
(name got expected)
|
|
(if
|
|
(dl-demo-set=? got expected)
|
|
(set! dl-demo-pass (+ dl-demo-pass 1))
|
|
(do
|
|
(set! dl-demo-fail (+ dl-demo-fail 1))
|
|
(append!
|
|
dl-demo-failures
|
|
(str
|
|
name
|
|
"\n expected (set): " expected
|
|
"\n got: " got))))))
|
|
|
|
(define
|
|
dl-demo-run-all!
|
|
(fn
|
|
()
|
|
(do
|
|
;; ── Federation ──────────────────────────────────────────
|
|
(dl-demo-test-set! "mutuals"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote ((follows alice bob) (follows bob alice)
|
|
(follows bob carol) (follows carol dave)))
|
|
dl-demo-federation-rules)
|
|
(quote (mutual alice X)))
|
|
(list {:X (quote bob)}))
|
|
|
|
(dl-demo-test-set! "reachable transitive"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote ((follows alice bob) (follows bob carol) (follows carol dave)))
|
|
dl-demo-federation-rules)
|
|
(quote (reachable alice X)))
|
|
(list {:X (quote bob)} {:X (quote carol)} {:X (quote dave)}))
|
|
|
|
(dl-demo-test-set! "foaf"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote ((follows alice bob) (follows bob carol) (follows alice dave)))
|
|
dl-demo-federation-rules)
|
|
(quote (foaf alice X)))
|
|
(list {:X (quote carol)}))
|
|
|
|
;; ── Content ─────────────────────────────────────────────
|
|
(dl-demo-test-set! "popular posts"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote
|
|
((authored alice p1) (authored bob p2) (authored carol p3)
|
|
(liked u1 p1) (liked u2 p1) (liked u3 p1)
|
|
(liked u1 p2)))
|
|
dl-demo-content-rules)
|
|
(quote (popular P)))
|
|
(list {:P (quote p1)}))
|
|
|
|
(dl-demo-test-set! "interesting feed"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote
|
|
((follows me alice) (follows me bob)
|
|
(authored alice p1) (authored bob p2)
|
|
(liked u1 p1) (liked u2 p1) (liked u3 p1)
|
|
(liked u4 p2)))
|
|
dl-demo-content-rules)
|
|
(quote (interesting me P)))
|
|
(list {:P (quote p1)}))
|
|
|
|
(dl-demo-test-set! "post likes count"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote
|
|
((authored alice p1)
|
|
(liked u1 p1) (liked u2 p1) (liked u3 p1)))
|
|
dl-demo-content-rules)
|
|
(quote (post-likes p1 N)))
|
|
(list {:N 3}))
|
|
|
|
;; ── Permissions ─────────────────────────────────────────
|
|
(dl-demo-test-set! "direct group access"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote
|
|
((member alice editors)
|
|
(allowed editors blog)))
|
|
dl-demo-perm-rules)
|
|
(quote (can-access X blog)))
|
|
(list {:X (quote alice)}))
|
|
|
|
(dl-demo-test-set! "subgroup access"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote
|
|
((member bob writers)
|
|
(subgroup writers editors)
|
|
(allowed editors blog)))
|
|
dl-demo-perm-rules)
|
|
(quote (can-access X blog)))
|
|
(list {:X (quote bob)}))
|
|
|
|
(dl-demo-test-set! "transitive subgroup"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote
|
|
((member carol drafters)
|
|
(subgroup drafters writers)
|
|
(subgroup writers editors)
|
|
(allowed editors blog)))
|
|
dl-demo-perm-rules)
|
|
(quote (can-access X blog)))
|
|
(list {:X (quote carol)}))
|
|
|
|
(dl-demo-test-set! "no access without grant"
|
|
(dl-query
|
|
(dl-demo-make
|
|
(quote ((member dave outsiders) (allowed editors blog)))
|
|
dl-demo-perm-rules)
|
|
(quote (can-access X blog)))
|
|
(list)))))
|
|
|
|
(define
|
|
dl-demo-tests-run!
|
|
(fn
|
|
()
|
|
(do
|
|
(set! dl-demo-pass 0)
|
|
(set! dl-demo-fail 0)
|
|
(set! dl-demo-failures (list))
|
|
(dl-demo-run-all!)
|
|
{:passed dl-demo-pass
|
|
:failed dl-demo-fail
|
|
:total (+ dl-demo-pass dl-demo-fail)
|
|
:failures dl-demo-failures})))
|