;; lib/datalog/demo.sx — example programs over rose-ash-shaped data. ;; ;; Phase 10 prototypes Datalog as a rose-ash query language. Wiring ;; the EDB to actual PostgreSQL is out of scope for this loop (it ;; would touch service code outside lib/datalog/), but the programs ;; below show the shape of queries we want, and the test suite runs ;; them against synthetic in-memory tuples loaded via dl-program-data. ;; ;; Seven thematic demos: ;; ;; 1. Federation — follow graph, transitive reach, mutuals, FOAF. ;; 2. Content — posts, tags, likes, popularity, "for you" feed. ;; 3. Permissions — group membership and resource access. ;; 4. Cooking-posts — canonical "posts about cooking by people I ;; follow (transitively)" multi-domain query. ;; 5. Tag co-occurrence — distinct (T1, T2) pairs with counts. ;; 6. Shortest path — weighted-DAG path enumeration + min agg. ;; 7. Org chart — transitive subordinate + headcount per mgr. ;; ── Demo 1: federation follow graph ───────────────────────────── ;; EDB: (follows ACTOR-A ACTOR-B) — A follows B. ;; IDB: ;; (mutual A B) — A follows B and B follows A ;; (reachable A B) — transitive follow closure ;; (foaf A C) — friend of a friend (mutual filter) (define dl-demo-federation-rules (quote ((mutual A B <- (follows A B) (follows B A)) (reachable A B <- (follows A B)) (reachable A C <- (follows A B) (reachable B C)) (foaf A C <- (follows A B) (follows B C) (!= A C))))) ;; ── Demo 2: content recommendation ────────────────────────────── ;; EDB: ;; (authored ACTOR POST) ;; (tagged POST TAG) ;; (liked ACTOR POST) ;; IDB: ;; (post-likes POST N) — count of likes per post ;; (popular POST) — posts with >= 3 likes ;; (tagged-by-mutual ACTOR POST) — post tagged TOPIC by someone ;; A's mutuals follow. (define dl-demo-content-rules (quote ((post-likes P N <- (authored Author P) (count N L (liked L P))) (popular P <- (authored Author P) (post-likes P N) (>= N 3)) (interesting Me P <- (follows Me Buddy) (authored Buddy P) (popular P))))) ;; ── Demo 3: role-based permissions ────────────────────────────── ;; EDB: ;; (member ACTOR GROUP) ;; (subgroup CHILD PARENT) ;; (allowed GROUP RESOURCE) ;; IDB: ;; (in-group ACTOR GROUP) — direct or via subgroup chain ;; (can-access ACTOR RESOURCE) — actor inherits group permission (define dl-demo-perm-rules (quote ((in-group A G <- (member A G)) (in-group A G <- (member A H) (subgroup-trans H G)) (subgroup-trans X Y <- (subgroup X Y)) (subgroup-trans X Z <- (subgroup X Y) (subgroup-trans Y Z)) (can-access A R <- (in-group A G) (allowed G R))))) ;; ── Demo 4: cooking-posts (the canonical Phase 10 query) ──────── ;; "Posts about cooking by people I follow (transitively)." ;; Combines federation (follows + transitive reach), authoring, ;; tagging — the rose-ash multi-domain join. ;; ;; EDB: ;; (follows ACTOR-A ACTOR-B) ;; (authored ACTOR POST) ;; (tagged POST TAG) (define dl-demo-cooking-rules (quote ((reach Me Them <- (follows Me Them)) (reach Me Them <- (follows Me X) (reach X Them)) (cooking-post-by-network Me P <- (reach Me Author) (authored Author P) (tagged P cooking))))) ;; ── Demo 5: tag co-occurrence ─────────────────────────────────── ;; "Posts tagged with both T1 AND T2." Useful for narrowed-down ;; recommendations like "vegetarian cooking" posts. ;; ;; EDB: ;; (tagged POST TAG) ;; IDB: ;; (cotagged POST T1 T2) — post has both T1 and T2 (T1 != T2) ;; (popular-pair T1 T2 N) — count of posts cotagged (T1, T2) (define dl-demo-tag-cooccur-rules (quote ((cotagged P T1 T2 <- (tagged P T1) (tagged P T2) (!= T1 T2)) ;; Distinct (T1, T2) pairs that occur somewhere. (tag-pair T1 T2 <- (cotagged P T1 T2)) (tag-pair-count T1 T2 N <- (tag-pair T1 T2) (count N P (cotagged P T1 T2)))))) ;; ── Demo 6: weighted-DAG shortest path ───────────────────────── ;; "What's the cheapest way from X to Y?" Edge weights with `is` ;; arithmetic to sum costs, then `min` aggregation to pick the ;; shortest. Termination requires the graph to be a DAG (cycles ;; would produce infinite distances without a bound; programs ;; built on this should add a depth filter `(<, D, MAX)` if cycles ;; are possible). ;; ;; EDB: ;; (edge FROM TO COST) ;; IDB: ;; (path FROM TO COST) — any path ;; (shortest FROM TO COST) — minimum cost path (define dl-demo-shortest-path-rules (quote ((path X Y W <- (edge X Y W)) (path X Z W <- (edge X Y W1) (path Y Z W2) (is W (+ W1 W2))) (shortest X Y W <- (path X Y _) (min W C (path X Y C)))))) ;; ── Demo 7: org chart + transitive headcount ─────────────────── ;; Manager graph: each employee has a single manager. Compute the ;; transitive subordinate set and headcount per manager. ;; ;; EDB: ;; (manager EMP MGR) — EMP reports directly to MGR ;; IDB: ;; (subordinate MGR EMP) — EMP is in MGR's subtree ;; (headcount MGR N) — number of subordinates under MGR (define dl-demo-org-rules (quote ((subordinate Mgr Emp <- (manager Emp Mgr)) (subordinate Mgr Emp <- (manager Mid Mgr) (subordinate Mid Emp)) (headcount Mgr N <- (subordinate Mgr Anyone) (count N E (subordinate Mgr E)))))) ;; ── Loader stub ────────────────────────────────────────────────── ;; Wiring to PostgreSQL would replace these helpers with calls into ;; rose-ash's internal HTTP RPC (fetch_data → /internal/data/...). ;; The shape returned by dl-load-from-edb! is the same in either case. (define dl-demo-make (fn (facts rules) (dl-program-data facts rules)))