@suss/datalog 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +34 -18
- package/dist/index.js +34 -18
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -665,38 +665,46 @@ function stratify(rules) {
|
|
|
665
665
|
}
|
|
666
666
|
return strata.filter((s) => s.length > 0);
|
|
667
667
|
}
|
|
668
|
+
function boundValue(bindings, name) {
|
|
669
|
+
for (let b = bindings; b !== null; b = b.parent) {
|
|
670
|
+
if (b.name === name) {
|
|
671
|
+
return b.value;
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return void 0;
|
|
675
|
+
}
|
|
676
|
+
var NO_MATCH = /* @__PURE__ */ Symbol("no-match");
|
|
668
677
|
function unify(literal, tuple, bindings) {
|
|
669
678
|
if (literal.terms.length !== tuple.length) {
|
|
670
|
-
return
|
|
679
|
+
return NO_MATCH;
|
|
671
680
|
}
|
|
672
|
-
let next =
|
|
681
|
+
let next = bindings;
|
|
673
682
|
for (let i = 0; i < literal.terms.length; i++) {
|
|
674
683
|
const term = literal.terms[i];
|
|
675
684
|
const value = tuple[i];
|
|
676
685
|
if (term.type === "constant") {
|
|
677
686
|
if (term.value !== value) {
|
|
678
|
-
return
|
|
687
|
+
return NO_MATCH;
|
|
679
688
|
}
|
|
680
689
|
continue;
|
|
681
690
|
}
|
|
682
|
-
const bound = (next
|
|
691
|
+
const bound = boundValue(next, term.name);
|
|
683
692
|
if (bound === void 0) {
|
|
684
|
-
next =
|
|
685
|
-
next.set(term.name, value);
|
|
693
|
+
next = { name: term.name, value, parent: next };
|
|
686
694
|
continue;
|
|
687
695
|
}
|
|
688
696
|
if (bound !== value) {
|
|
689
|
-
return
|
|
697
|
+
return NO_MATCH;
|
|
690
698
|
}
|
|
691
699
|
}
|
|
692
|
-
return next
|
|
700
|
+
return next;
|
|
693
701
|
}
|
|
694
702
|
function groundNegated(literal, bindings) {
|
|
695
703
|
return literal.terms.map((term) => {
|
|
696
704
|
if (term.type === "constant") {
|
|
697
705
|
return term.value;
|
|
698
706
|
}
|
|
699
|
-
const bound = bindings
|
|
707
|
+
const bound = boundValue(bindings, term.name);
|
|
700
708
|
if (bound === void 0) {
|
|
701
709
|
throw new Error(
|
|
702
710
|
`unbound variable "${term.name}" in negated literal "${literal.relation}": negated literals may only use variables bound by earlier positive literals`
|
|
@@ -710,7 +718,7 @@ function headTuple(head, bindings) {
|
|
|
710
718
|
if (term.type === "constant") {
|
|
711
719
|
return term.value;
|
|
712
720
|
}
|
|
713
|
-
const bound = bindings
|
|
721
|
+
const bound = boundValue(bindings, term.name);
|
|
714
722
|
if (bound === void 0) {
|
|
715
723
|
throw new Error(
|
|
716
724
|
`unbound variable "${term.name}" in head of "${head.relation}"`
|
|
@@ -736,23 +744,31 @@ function evaluateRule(db, deltas, r, deltaIndex) {
|
|
|
736
744
|
const source = positiveIndex === deltaIndex ? deltas.get(literal.relation) ?? [] : boundSource(db, literal, bindings);
|
|
737
745
|
for (const tuple of source) {
|
|
738
746
|
const next = unify(literal, tuple, bindings);
|
|
739
|
-
if (next !==
|
|
747
|
+
if (next !== NO_MATCH) {
|
|
740
748
|
step(literalIndex + 1, positiveIndex + 1, next);
|
|
741
749
|
}
|
|
742
750
|
}
|
|
743
751
|
};
|
|
744
|
-
step(0, 0,
|
|
752
|
+
step(0, 0, null);
|
|
745
753
|
return results;
|
|
746
754
|
}
|
|
747
755
|
function boundSource(db, literal, bindings) {
|
|
756
|
+
let narrowest = null;
|
|
748
757
|
for (let column = 0; column < literal.terms.length; column++) {
|
|
749
758
|
const term = literal.terms[column];
|
|
750
|
-
const value = term.type === "constant" ? term.value : bindings
|
|
751
|
-
if (value
|
|
752
|
-
|
|
759
|
+
const value = term.type === "constant" ? term.value : boundValue(bindings, term.name);
|
|
760
|
+
if (value === void 0) {
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const bucket = db.lookup(literal.relation, column, value);
|
|
764
|
+
if (bucket.length === 0) {
|
|
765
|
+
return bucket;
|
|
766
|
+
}
|
|
767
|
+
if (narrowest === null || bucket.length < narrowest.length) {
|
|
768
|
+
narrowest = bucket;
|
|
753
769
|
}
|
|
754
770
|
}
|
|
755
|
-
return db.facts(literal.relation);
|
|
771
|
+
return narrowest ?? db.facts(literal.relation);
|
|
756
772
|
}
|
|
757
773
|
var EMPTY_TAGS = [];
|
|
758
774
|
function evaluateRuleTagged(db, deltas, r, deltaIndex, algebra) {
|
|
@@ -794,7 +810,7 @@ function evaluateRuleTagged(db, deltas, r, deltaIndex, algebra) {
|
|
|
794
810
|
const source = positiveIndex === deltaIndex ? deltas.get(literal.relation) ?? [] : boundSource(db, literal, bindings);
|
|
795
811
|
for (const tuple of source) {
|
|
796
812
|
const next = unify(literal, tuple, bindings);
|
|
797
|
-
if (next !==
|
|
813
|
+
if (next !== NO_MATCH) {
|
|
798
814
|
if (readsTags) {
|
|
799
815
|
const stored = db.tagOf(literal.relation, tuple);
|
|
800
816
|
bodyTags.push(
|
|
@@ -814,7 +830,7 @@ function evaluateRuleTagged(db, deltas, r, deltaIndex, algebra) {
|
|
|
814
830
|
}
|
|
815
831
|
}
|
|
816
832
|
};
|
|
817
|
-
step(0, 0,
|
|
833
|
+
step(0, 0, null);
|
|
818
834
|
return results;
|
|
819
835
|
}
|
|
820
836
|
var evaluated = /* @__PURE__ */ new WeakMap();
|
package/dist/index.js
CHANGED
|
@@ -619,38 +619,46 @@ function stratify(rules) {
|
|
|
619
619
|
}
|
|
620
620
|
return strata.filter((s) => s.length > 0);
|
|
621
621
|
}
|
|
622
|
+
function boundValue(bindings, name) {
|
|
623
|
+
for (let b = bindings; b !== null; b = b.parent) {
|
|
624
|
+
if (b.name === name) {
|
|
625
|
+
return b.value;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return void 0;
|
|
629
|
+
}
|
|
630
|
+
var NO_MATCH = /* @__PURE__ */ Symbol("no-match");
|
|
622
631
|
function unify(literal, tuple, bindings) {
|
|
623
632
|
if (literal.terms.length !== tuple.length) {
|
|
624
|
-
return
|
|
633
|
+
return NO_MATCH;
|
|
625
634
|
}
|
|
626
|
-
let next =
|
|
635
|
+
let next = bindings;
|
|
627
636
|
for (let i = 0; i < literal.terms.length; i++) {
|
|
628
637
|
const term = literal.terms[i];
|
|
629
638
|
const value = tuple[i];
|
|
630
639
|
if (term.type === "constant") {
|
|
631
640
|
if (term.value !== value) {
|
|
632
|
-
return
|
|
641
|
+
return NO_MATCH;
|
|
633
642
|
}
|
|
634
643
|
continue;
|
|
635
644
|
}
|
|
636
|
-
const bound = (next
|
|
645
|
+
const bound = boundValue(next, term.name);
|
|
637
646
|
if (bound === void 0) {
|
|
638
|
-
next =
|
|
639
|
-
next.set(term.name, value);
|
|
647
|
+
next = { name: term.name, value, parent: next };
|
|
640
648
|
continue;
|
|
641
649
|
}
|
|
642
650
|
if (bound !== value) {
|
|
643
|
-
return
|
|
651
|
+
return NO_MATCH;
|
|
644
652
|
}
|
|
645
653
|
}
|
|
646
|
-
return next
|
|
654
|
+
return next;
|
|
647
655
|
}
|
|
648
656
|
function groundNegated(literal, bindings) {
|
|
649
657
|
return literal.terms.map((term) => {
|
|
650
658
|
if (term.type === "constant") {
|
|
651
659
|
return term.value;
|
|
652
660
|
}
|
|
653
|
-
const bound = bindings
|
|
661
|
+
const bound = boundValue(bindings, term.name);
|
|
654
662
|
if (bound === void 0) {
|
|
655
663
|
throw new Error(
|
|
656
664
|
`unbound variable "${term.name}" in negated literal "${literal.relation}": negated literals may only use variables bound by earlier positive literals`
|
|
@@ -664,7 +672,7 @@ function headTuple(head, bindings) {
|
|
|
664
672
|
if (term.type === "constant") {
|
|
665
673
|
return term.value;
|
|
666
674
|
}
|
|
667
|
-
const bound = bindings
|
|
675
|
+
const bound = boundValue(bindings, term.name);
|
|
668
676
|
if (bound === void 0) {
|
|
669
677
|
throw new Error(
|
|
670
678
|
`unbound variable "${term.name}" in head of "${head.relation}"`
|
|
@@ -690,23 +698,31 @@ function evaluateRule(db, deltas, r, deltaIndex) {
|
|
|
690
698
|
const source = positiveIndex === deltaIndex ? deltas.get(literal.relation) ?? [] : boundSource(db, literal, bindings);
|
|
691
699
|
for (const tuple of source) {
|
|
692
700
|
const next = unify(literal, tuple, bindings);
|
|
693
|
-
if (next !==
|
|
701
|
+
if (next !== NO_MATCH) {
|
|
694
702
|
step(literalIndex + 1, positiveIndex + 1, next);
|
|
695
703
|
}
|
|
696
704
|
}
|
|
697
705
|
};
|
|
698
|
-
step(0, 0,
|
|
706
|
+
step(0, 0, null);
|
|
699
707
|
return results;
|
|
700
708
|
}
|
|
701
709
|
function boundSource(db, literal, bindings) {
|
|
710
|
+
let narrowest = null;
|
|
702
711
|
for (let column = 0; column < literal.terms.length; column++) {
|
|
703
712
|
const term = literal.terms[column];
|
|
704
|
-
const value = term.type === "constant" ? term.value : bindings
|
|
705
|
-
if (value
|
|
706
|
-
|
|
713
|
+
const value = term.type === "constant" ? term.value : boundValue(bindings, term.name);
|
|
714
|
+
if (value === void 0) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const bucket = db.lookup(literal.relation, column, value);
|
|
718
|
+
if (bucket.length === 0) {
|
|
719
|
+
return bucket;
|
|
720
|
+
}
|
|
721
|
+
if (narrowest === null || bucket.length < narrowest.length) {
|
|
722
|
+
narrowest = bucket;
|
|
707
723
|
}
|
|
708
724
|
}
|
|
709
|
-
return db.facts(literal.relation);
|
|
725
|
+
return narrowest ?? db.facts(literal.relation);
|
|
710
726
|
}
|
|
711
727
|
var EMPTY_TAGS = [];
|
|
712
728
|
function evaluateRuleTagged(db, deltas, r, deltaIndex, algebra) {
|
|
@@ -748,7 +764,7 @@ function evaluateRuleTagged(db, deltas, r, deltaIndex, algebra) {
|
|
|
748
764
|
const source = positiveIndex === deltaIndex ? deltas.get(literal.relation) ?? [] : boundSource(db, literal, bindings);
|
|
749
765
|
for (const tuple of source) {
|
|
750
766
|
const next = unify(literal, tuple, bindings);
|
|
751
|
-
if (next !==
|
|
767
|
+
if (next !== NO_MATCH) {
|
|
752
768
|
if (readsTags) {
|
|
753
769
|
const stored = db.tagOf(literal.relation, tuple);
|
|
754
770
|
bodyTags.push(
|
|
@@ -768,7 +784,7 @@ function evaluateRuleTagged(db, deltas, r, deltaIndex, algebra) {
|
|
|
768
784
|
}
|
|
769
785
|
}
|
|
770
786
|
};
|
|
771
|
-
step(0, 0,
|
|
787
|
+
step(0, 0, null);
|
|
772
788
|
return results;
|
|
773
789
|
}
|
|
774
790
|
var evaluated = /* @__PURE__ */ new WeakMap();
|
package/package.json
CHANGED