@suss/datalog 0.21.1 → 0.22.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/README.md CHANGED
@@ -313,6 +313,24 @@ Keep the facts you add and the facts the rules derive in separate
313
313
  relations. Taking a conclusion back cannot tell one from the other, and
314
314
  splitting them is how people normally write Datalog anyway.
315
315
 
316
+ ### Reading what the rules are waiting on
317
+
318
+ Demand is also something a caller can read. `program.demands` lists
319
+ each demand relation with the relation it is for and which of that
320
+ relation's columns a demand row fixes, in column order:
321
+
322
+ ```ts
323
+ program.demands;
324
+ // [{ relation: "reaches", bound: [true, false], demand: "wanted:reaches" }]
325
+ db.facts("wanted:reaches"); // [["a"], ["b"], ["c"]]
326
+ ```
327
+
328
+ A caller that loads its base facts lazily uses this to find out what to
329
+ load next. Evaluate, read the demand rows on the relation whose base
330
+ facts come from somewhere else, fetch those, evaluate again, and stop
331
+ when no demand row is new. The rules then decide what gets loaded, and
332
+ the caller never has to guess how far a chain runs.
333
+
316
334
  Extraction-scale fact sets run to thousands of tuples. If that changes,
317
335
  the rule data model is the part that stays and this evaluator is the
318
336
  part you replace.
package/dist/index.cjs CHANGED
@@ -117,6 +117,7 @@ function deriveOnDemand(rules, complete) {
117
117
  const demandOn = (relation, adornment) => `wanted:${nameOf(relation, adornment)}`;
118
118
  const rewritten = [];
119
119
  const demandDriven = /* @__PURE__ */ new Set();
120
+ const demands = [];
120
121
  const already = /* @__PURE__ */ new Set();
121
122
  const emit = (r) => {
122
123
  const key = JSON.stringify(r);
@@ -129,6 +130,11 @@ function deriveOnDemand(rules, complete) {
129
130
  if (anyBound(adorned.adornment)) {
130
131
  demandDriven.add(nameOf(adorned.relation, adorned.adornment));
131
132
  demandDriven.add(demandOn(adorned.relation, adorned.adornment));
133
+ demands.push({
134
+ relation: adorned.relation,
135
+ bound: adorned.adornment,
136
+ demand: demandOn(adorned.relation, adorned.adornment)
137
+ });
132
138
  }
133
139
  for (const written of rulesByHead.get(adorned.relation) ?? []) {
134
140
  const r = boundFirst(written, adorned.adornment);
@@ -169,7 +175,7 @@ function deriveOnDemand(rules, complete) {
169
175
  }
170
176
  }
171
177
  demandRewrites.add(rewritten);
172
- return { rules: rewritten, demandDriven: [...demandDriven] };
178
+ return { rules: rewritten, demandDriven: [...demandDriven], demands };
173
179
  }
174
180
  var sameLiteral = (premises, conclusion) => premises.length === 1 && JSON.stringify(premises[0]) === JSON.stringify(conclusion);
175
181
  function boundFirst(r, headAdornment) {
package/dist/index.d.cts CHANGED
@@ -31,6 +31,18 @@ declare function confidenceWith(levelOf: (rule: Rule) => ConfidenceLevel | undef
31
31
  /** The confidence algebra with every rule counted as exact. */
32
32
  declare const confidence: TagAlgebra<ConfidenceLevel>;
33
33
 
34
+ /** One demand relation the rewrite created, and what its rows say. */
35
+ interface Demand {
36
+ /** The relation whose rows are being waited on. */
37
+ relation: string;
38
+ /** Which columns of that relation a demand row fixes. */
39
+ bound: readonly boolean[];
40
+ /**
41
+ * The demand relation's name. Each of its rows lists the bound
42
+ * columns' values, in the relation's column order.
43
+ */
44
+ demand: string;
45
+ }
34
46
  /** A rewritten rule set, and which of its relations demand restricts. */
35
47
  interface OnDemandRules {
36
48
  /** The rewritten rules, ready to evaluate. */
@@ -43,6 +55,13 @@ interface OnDemandRules {
43
55
  * answers.
44
56
  */
45
57
  demandDriven: string[];
58
+ /**
59
+ * The demand relations by what they ask for, so a caller can read
60
+ * what the rules are waiting on and go and get it: a store that
61
+ * loads facts lazily reads the demand on a module's exports and
62
+ * extracts that module.
63
+ */
64
+ demands: Demand[];
46
65
  }
47
66
  /**
48
67
  * Rewrite `rules` so the relations listed in `complete` still come out
@@ -419,4 +438,4 @@ declare function evaluate<Tag = never>(db: Database, rules: Rule[], algebra?: Ta
419
438
  */
420
439
  declare function clearRelations(db: Database, rules: Rule[], relations: readonly string[]): void;
421
440
 
422
- export { type AddOutcome, type Atom, type BodyMatch, type ConfidenceLevel, Database, type Derivation, type EvaluationProfile, type Literal, type OnDemandRules, type Proof, type ProofDerived, type ProofOptions, type Rule, type RuleCost, type TagAlgebra, type Term, type Tuple, Witness, type WitnessTag, clearRelations, confidence, confidenceWith, constant, deriveOnDemand, evaluate, formatProfile, lit, notLit, profileEvaluation, profileEvaluationAsync, proofOf, rule, ruleLabel, stratify, tupleKey, tupleKeyParts, variable, witnesses };
441
+ export { type AddOutcome, type Atom, type BodyMatch, type ConfidenceLevel, Database, type Demand, type Derivation, type EvaluationProfile, type Literal, type OnDemandRules, type Proof, type ProofDerived, type ProofOptions, type Rule, type RuleCost, type TagAlgebra, type Term, type Tuple, Witness, type WitnessTag, clearRelations, confidence, confidenceWith, constant, deriveOnDemand, evaluate, formatProfile, lit, notLit, profileEvaluation, profileEvaluationAsync, proofOf, rule, ruleLabel, stratify, tupleKey, tupleKeyParts, variable, witnesses };
package/dist/index.d.ts CHANGED
@@ -31,6 +31,18 @@ declare function confidenceWith(levelOf: (rule: Rule) => ConfidenceLevel | undef
31
31
  /** The confidence algebra with every rule counted as exact. */
32
32
  declare const confidence: TagAlgebra<ConfidenceLevel>;
33
33
 
34
+ /** One demand relation the rewrite created, and what its rows say. */
35
+ interface Demand {
36
+ /** The relation whose rows are being waited on. */
37
+ relation: string;
38
+ /** Which columns of that relation a demand row fixes. */
39
+ bound: readonly boolean[];
40
+ /**
41
+ * The demand relation's name. Each of its rows lists the bound
42
+ * columns' values, in the relation's column order.
43
+ */
44
+ demand: string;
45
+ }
34
46
  /** A rewritten rule set, and which of its relations demand restricts. */
35
47
  interface OnDemandRules {
36
48
  /** The rewritten rules, ready to evaluate. */
@@ -43,6 +55,13 @@ interface OnDemandRules {
43
55
  * answers.
44
56
  */
45
57
  demandDriven: string[];
58
+ /**
59
+ * The demand relations by what they ask for, so a caller can read
60
+ * what the rules are waiting on and go and get it: a store that
61
+ * loads facts lazily reads the demand on a module's exports and
62
+ * extracts that module.
63
+ */
64
+ demands: Demand[];
46
65
  }
47
66
  /**
48
67
  * Rewrite `rules` so the relations listed in `complete` still come out
@@ -419,4 +438,4 @@ declare function evaluate<Tag = never>(db: Database, rules: Rule[], algebra?: Ta
419
438
  */
420
439
  declare function clearRelations(db: Database, rules: Rule[], relations: readonly string[]): void;
421
440
 
422
- export { type AddOutcome, type Atom, type BodyMatch, type ConfidenceLevel, Database, type Derivation, type EvaluationProfile, type Literal, type OnDemandRules, type Proof, type ProofDerived, type ProofOptions, type Rule, type RuleCost, type TagAlgebra, type Term, type Tuple, Witness, type WitnessTag, clearRelations, confidence, confidenceWith, constant, deriveOnDemand, evaluate, formatProfile, lit, notLit, profileEvaluation, profileEvaluationAsync, proofOf, rule, ruleLabel, stratify, tupleKey, tupleKeyParts, variable, witnesses };
441
+ export { type AddOutcome, type Atom, type BodyMatch, type ConfidenceLevel, Database, type Demand, type Derivation, type EvaluationProfile, type Literal, type OnDemandRules, type Proof, type ProofDerived, type ProofOptions, type Rule, type RuleCost, type TagAlgebra, type Term, type Tuple, Witness, type WitnessTag, clearRelations, confidence, confidenceWith, constant, deriveOnDemand, evaluate, formatProfile, lit, notLit, profileEvaluation, profileEvaluationAsync, proofOf, rule, ruleLabel, stratify, tupleKey, tupleKeyParts, variable, witnesses };
package/dist/index.js CHANGED
@@ -71,6 +71,7 @@ function deriveOnDemand(rules, complete) {
71
71
  const demandOn = (relation, adornment) => `wanted:${nameOf(relation, adornment)}`;
72
72
  const rewritten = [];
73
73
  const demandDriven = /* @__PURE__ */ new Set();
74
+ const demands = [];
74
75
  const already = /* @__PURE__ */ new Set();
75
76
  const emit = (r) => {
76
77
  const key = JSON.stringify(r);
@@ -83,6 +84,11 @@ function deriveOnDemand(rules, complete) {
83
84
  if (anyBound(adorned.adornment)) {
84
85
  demandDriven.add(nameOf(adorned.relation, adorned.adornment));
85
86
  demandDriven.add(demandOn(adorned.relation, adorned.adornment));
87
+ demands.push({
88
+ relation: adorned.relation,
89
+ bound: adorned.adornment,
90
+ demand: demandOn(adorned.relation, adorned.adornment)
91
+ });
86
92
  }
87
93
  for (const written of rulesByHead.get(adorned.relation) ?? []) {
88
94
  const r = boundFirst(written, adorned.adornment);
@@ -123,7 +129,7 @@ function deriveOnDemand(rules, complete) {
123
129
  }
124
130
  }
125
131
  demandRewrites.add(rewritten);
126
- return { rules: rewritten, demandDriven: [...demandDriven] };
132
+ return { rules: rewritten, demandDriven: [...demandDriven], demands };
127
133
  }
128
134
  var sameLiteral = (premises, conclusion) => premises.length === 1 && JSON.stringify(premises[0]) === JSON.stringify(conclusion);
129
135
  function boundFirst(r, headAdornment) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/datalog",
3
- "version": "0.21.1",
3
+ "version": "0.22.0",
4
4
  "type": "module",
5
5
  "description": "A small semi-naïve Datalog evaluator with stratified negation — the rules engine behind suss's derived program facts.",
6
6
  "keywords": [