diff --git a/lib/datalog/magic.sx b/lib/datalog/magic.sx index 7ea1b548..4a2953f0 100644 --- a/lib/datalog/magic.sx +++ b/lib/datalog/magic.sx @@ -376,16 +376,26 @@ dl-magic-query (fn (db query-goal) - (let - ((query-rel (dl-rel-name query-goal)) - (query-adn (dl-adorn-goal query-goal))) - (let - ((query-args (dl-bound-args query-goal query-adn)) - (rules (dl-rules db))) + ;; Magic-sets only applies to positive non-builtin / non-aggregate + ;; literals against rule-defined relations. For other goal shapes + ;; (built-ins, aggregates, EDB-only relations) the seed is either + ;; non-ground or unused; fall back to dl-query. + (cond + ((or (dl-builtin? query-goal) + (dl-aggregate? query-goal) + (and (dict? query-goal) (has-key? query-goal :neg))) + (dl-query db query-goal)) + (else (let - ((rewritten (dl-magic-rewrite rules query-rel query-adn query-args)) - (mdb (dl-make-db)) - (rule-heads (dl-magic-rule-heads rules))) + ((query-rel (dl-rel-name query-goal)) + (query-adn (dl-adorn-goal query-goal))) + (let + ((query-args (dl-bound-args query-goal query-adn)) + (rules (dl-rules db))) + (let + ((rewritten (dl-magic-rewrite rules query-rel query-adn query-args)) + (mdb (dl-make-db)) + (rule-heads (dl-magic-rule-heads rules))) (do ;; Copy EDB facts (relations not headed by any caller rule). (for-each @@ -400,4 +410,4 @@ ;; Seed + rewritten rules. (dl-add-fact! mdb (get rewritten :seed)) (for-each (fn (r) (dl-add-rule! mdb r)) (get rewritten :rules)) - (dl-query mdb query-goal))))))) + (dl-query mdb query-goal))))))))) diff --git a/lib/datalog/scoreboard.json b/lib/datalog/scoreboard.json index b1366855..2c9f5834 100644 --- a/lib/datalog/scoreboard.json +++ b/lib/datalog/scoreboard.json @@ -1,8 +1,8 @@ { "lang": "datalog", - "total_passed": 221, + "total_passed": 222, "total_failed": 0, - "total": 221, + "total": 222, "suites": [ {"name":"tokenize","passed":26,"failed":0,"total":26}, {"name":"parse","passed":18,"failed":0,"total":18}, @@ -13,8 +13,8 @@ {"name":"negation","passed":10,"failed":0,"total":10}, {"name":"aggregates","passed":19,"failed":0,"total":19}, {"name":"api","passed":20,"failed":0,"total":20}, - {"name":"magic","passed":23,"failed":0,"total":23}, + {"name":"magic","passed":24,"failed":0,"total":24}, {"name":"demo","passed":21,"failed":0,"total":21} ], - "generated": "2026-05-08T10:29:04+00:00" + "generated": "2026-05-08T10:31:43+00:00" } diff --git a/lib/datalog/scoreboard.md b/lib/datalog/scoreboard.md index dda4e89d..7b0b251a 100644 --- a/lib/datalog/scoreboard.md +++ b/lib/datalog/scoreboard.md @@ -1,6 +1,6 @@ # datalog scoreboard -**221 / 221 passing** (0 failure(s)). +**222 / 222 passing** (0 failure(s)). | Suite | Passed | Total | Status | |-------|--------|-------|--------| @@ -13,5 +13,5 @@ | negation | 10 | 10 | ok | | aggregates | 19 | 19 | ok | | api | 20 | 20 | ok | -| magic | 23 | 23 | ok | +| magic | 24 | 24 | ok | | demo | 21 | 21 | ok | diff --git a/lib/datalog/tests/magic.sx b/lib/datalog/tests/magic.sx index d5a6ca0f..e9ebefb3 100644 --- a/lib/datalog/tests/magic.sx +++ b/lib/datalog/tests/magic.sx @@ -197,6 +197,18 @@ 6) ;; dl-magic-query: end-to-end driver, doesn't mutate caller's db. + ;; dl-magic-query falls back to dl-query for built-in, + ;; aggregate, and negation goals (the magic seed would + ;; otherwise be non-ground). + (dl-mt-test! "magic-query falls back on aggregate" + (let + ((r (dl-magic-query + (dl-program "p(1). p(2). p(3).") + (list (quote count) (quote N) (quote X) + (list (quote p) (quote X)))))) + (and (= (len r) 1) (= (get (first r) "N") 3))) + true) + (dl-mt-test! "magic-query equivalent to dl-query" (let ((db (dl-program