eyeling 1.29.0 → 1.29.1

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
@@ -454,7 +454,7 @@ await runAsync(input, {
454
454
  });
455
455
  ```
456
456
 
457
- Persistent stores use a term dictionary plus `spo`, `pos`, and `osp` triple indexes. Exact lookup and all subject/predicate/object bound-pattern scans are available through the `FactStore` API:
457
+ Named persistent stores are created automatically when first opened. Persistent stores use a term dictionary plus `spo`, `pos`, and `osp` triple indexes. Exact lookup and all subject/predicate/object bound-pattern scans are available through the `FactStore` API:
458
458
 
459
459
  ```js
460
460
  const { createFactStore, rdfjs } = require('eyeling');
@@ -482,6 +482,12 @@ eyeling input.n3 --store my-dataset --store-clear
482
482
 
483
483
  eyeling input.n3 --store my-dataset --store-path ./.eyeling-store
484
484
  # Node.js path override
485
+
486
+ # Stream line-oriented RDF input into a store without reading one giant string.
487
+ eyeling --rdf big.nt --store my-dataset --store-path ./.eyeling-store
488
+
489
+ # Stream RDF Message Logs one message at a time and persist facts/inferences.
490
+ eyeling --rdf --stream-messages rules.n3 messages.trig --store my-dataset
485
491
  ```
486
492
 
487
493
  ### `reasonRdfJs(input, options)`
@@ -617,6 +623,12 @@ For one-message-at-a-time processing:
617
623
  eyeling --rdf --stream-messages rules.n3 messages.trig
618
624
  ```
619
625
 
626
+ `--stream-messages` can also be combined with `--store` to create/reuse a named store and persist each message's explicit facts and inferred facts while keeping only one replay message in memory at a time:
627
+
628
+ ```bash
629
+ eyeling --rdf --stream-messages rules.n3 messages.trig --store my-dataset --store-path ./.eyeling-store
630
+ ```
631
+
620
632
  Eyeling materializes a replay view under the `eymsg:` vocabulary:
621
633
 
622
634
  ```n3
@@ -1253,7 +1265,7 @@ reasonStream(input, { rdf: true });
1253
1265
 
1254
1266
  ### `--stream-messages` fails immediately
1255
1267
 
1256
- `--stream-messages` requires RDF mode and cannot be combined with `--ast`, `--stream`, or proof output.
1268
+ `--stream-messages` requires RDF mode and cannot be combined with `--ast`, `--stream`, or proof output. It can be combined with `--store`.
1257
1269
 
1258
1270
  Use:
1259
1271
 
@@ -5842,10 +5842,12 @@ function runParsedDocumentOnce(mergedDocument, { rdfMode = false, outputPrefixes
5842
5842
 
5843
5843
  let derived = [];
5844
5844
  let outTriples = [];
5845
+ let queryDerived = [];
5845
5846
  if (hasQueries) {
5846
5847
  const res = engine.forwardChainAndCollectLogQueryConclusions(facts, frules, brules, qrules, { prefixes });
5847
5848
  derived = res.derived;
5848
5849
  outTriples = res.queryTriples;
5850
+ queryDerived = res.queryDerived || [];
5849
5851
  } else {
5850
5852
  const skipDerivedCollection = mayAutoRenderOutputStrings;
5851
5853
  derived = engine.forwardChain(facts, frules, brules, null, {
@@ -5859,7 +5861,7 @@ function runParsedDocumentOnce(mergedDocument, { rdfMode = false, outputPrefixes
5859
5861
  const renderedOutputTriples = hasQueries ? outTriples : facts;
5860
5862
  if (factsContainOutputStrings(renderedOutputTriples)) {
5861
5863
  process.stdout.write(engine.collectOutputStringsFromFacts(renderedOutputTriples, prefixes));
5862
- return;
5864
+ return { facts, derived, outTriples, queryDerived, queryMode: !!hasQueries };
5863
5865
  }
5864
5866
 
5865
5867
  const outPrefixEnv = outputPrefixes || prefixes;
@@ -5871,9 +5873,99 @@ function runParsedDocumentOnce(mergedDocument, { rdfMode = false, outputPrefixes
5871
5873
  } else {
5872
5874
  for (const df of derived) console.log(engine.tripleToN3(df.fact, outPrefixEnv));
5873
5875
  }
5876
+ return { facts, derived, outTriples, queryDerived, queryMode: !!hasQueries };
5877
+ }
5878
+
5879
+ async function createCliStore({ storeName, storePath = null, storeClear = false } = {}) {
5880
+ if (!storeName) return null;
5881
+ return engine.createFactStore({ name: storeName, path: storePath || undefined, clear: !!storeClear });
5882
+ }
5883
+
5884
+ async function persistRunResultToStore(store, runResult) {
5885
+ if (!store || !runResult) return;
5886
+ await store.batchAdd(runResult.facts || [], 'explicit');
5887
+ await store.batchAdd((runResult.derived || []).map((df) => df.fact), 'inferred');
5888
+ await store.batchAdd((runResult.queryDerived || []).map((df) => df.fact), 'inferred');
5889
+ await store.batchAdd(runResult.outTriples || [], 'inferred');
5890
+ }
5891
+
5892
+ function sourceLooksLikeLineBasedRdf(sourceLabel) {
5893
+ if (typeof sourceLabel !== 'string') return false;
5894
+ const clean = sourceLabel.split(/[?#]/, 1)[0].toLowerCase();
5895
+ return /\.(?:nt|nq)(?:\.gz|\.br|\.deflate)?$/.test(clean);
5896
+ }
5897
+
5898
+ function parseLineBasedRdfLine(line, { sourceLabel, lineNumber, rdfMode }) {
5899
+ const text = String(line || '');
5900
+ if (!text.trim() || /^\s*#/.test(text)) return [];
5901
+ const doc = parseN3Text(text, {
5902
+ baseIri: __sourceLabelToBaseIri(sourceLabel),
5903
+ label: `${sourceLabel}:${lineNumber}`,
5904
+ keepSourceArtifacts: false,
5905
+ sourceLocations: false,
5906
+ rdf: rdfMode,
5907
+ });
5908
+ return doc.triples || [];
5909
+ }
5910
+
5911
+ async function ingestLineBasedRdfSourceToStore(sourceLabel, store, { rdfMode = true } = {}) {
5912
+ let lineNumber = 0;
5913
+ let count = 0;
5914
+ const onLine = async (line) => {
5915
+ lineNumber += 1;
5916
+ let triples;
5917
+ try {
5918
+ triples = parseLineBasedRdfLine(line, { sourceLabel, lineNumber, rdfMode });
5919
+ } catch (e) {
5920
+ if (e && e.name === 'N3SyntaxError') {
5921
+ throw new Error(formatN3SyntaxError(e, line, `${sourceLabel}:${lineNumber}`));
5922
+ }
5923
+ throw e;
5924
+ }
5925
+ count += await store.batchAdd(triples, 'explicit');
5926
+ };
5927
+
5928
+ const filePath = __localPathForSource(sourceLabel);
5929
+ if (filePath) {
5930
+ const fd = fs.openSync(filePath, 'r');
5931
+ const decoder = new TextDecoder('utf8');
5932
+ const buf = Buffer.allocUnsafe(64 * 1024);
5933
+ let carry = '';
5934
+ try {
5935
+ for (;;) {
5936
+ const n = fs.readSync(fd, buf, 0, buf.length, null);
5937
+ if (n === 0) break;
5938
+ carry += decoder.decode(buf.subarray(0, n), { stream: true });
5939
+ for (;;) {
5940
+ const m = /\r\n|\n|\r/.exec(carry);
5941
+ if (!m) break;
5942
+ const end = m.index + m[0].length;
5943
+ await onLine(carry.slice(0, end));
5944
+ carry = carry.slice(end);
5945
+ }
5946
+ }
5947
+ carry += decoder.decode();
5948
+ if (carry) await onLine(carry);
5949
+ } finally {
5950
+ fs.closeSync(fd);
5951
+ }
5952
+ return count;
5953
+ }
5954
+
5955
+ if (__isHttpSource(sourceLabel)) {
5956
+ const body = await __openHttpTextStream(sourceLabel);
5957
+ const rl = readline.createInterface({ input: body, crlfDelay: Infinity });
5958
+ for await (const line of rl) await onLine(line + '\n');
5959
+ return count;
5960
+ }
5961
+
5962
+ const text = __readInputSourceSync(sourceLabel);
5963
+ for (const line of text.match(/.*(?:\r\n|\n|\r)|.+$/g) || []) await onLine(line);
5964
+ return count;
5874
5965
  }
5875
5966
 
5876
- async function runStreamMessagesMode(sourceLabels, { rdfMode }) {
5967
+
5968
+ async function runStreamMessagesMode(sourceLabels, { rdfMode, storeName = null, storePath = null, storeClear = false } = {}) {
5877
5969
  const ordinarySourceLabels = [];
5878
5970
  const messageSourceLabels = [];
5879
5971
 
@@ -5922,40 +6014,49 @@ async function runStreamMessagesMode(sourceLabels, { rdfMode }) {
5922
6014
  }
5923
6015
  }
5924
6016
 
6017
+ const store = await createCliStore({ storeName, storePath, storeClear });
6018
+ let pendingStoreWrites = Promise.resolve();
6019
+
5925
6020
  const fullIriPrefixes = new PrefixEnv({});
5926
- for (const messageSourceLabel of messageSourceLabels) {
5927
- try {
5928
- await __forEachRdfMessageChunk(messageSourceLabel, ({ messageIndex, chunk, directives }) => {
5929
- const messageText = buildSingleMessageReplayDocument({
5930
- sourceLabel: messageSourceLabel,
5931
- messageIndex,
5932
- chunk,
5933
- directives,
5934
- });
5935
- let messageDoc;
5936
- try {
5937
- messageDoc = parseN3Text(messageText, {
5938
- baseIri: `${__sourceLabelToBaseIri(messageSourceLabel)}#message-${messageIndex}`,
5939
- label: `${messageSourceLabel}#message-${messageIndex}`,
5940
- keepSourceArtifacts: false,
5941
- sourceLocations: false,
5942
- rdf: false,
6021
+ try {
6022
+ for (const messageSourceLabel of messageSourceLabels) {
6023
+ try {
6024
+ await __forEachRdfMessageChunk(messageSourceLabel, ({ messageIndex, chunk, directives }) => {
6025
+ const messageText = buildSingleMessageReplayDocument({
6026
+ sourceLabel: messageSourceLabel,
6027
+ messageIndex,
6028
+ chunk,
6029
+ directives,
5943
6030
  });
5944
- } catch (e) {
5945
- if (e && e.name === 'N3SyntaxError') {
5946
- console.error(formatN3SyntaxError(e, messageText, `${messageSourceLabel}#message-${messageIndex}`));
5947
- process.exit(1);
6031
+ let messageDoc;
6032
+ try {
6033
+ messageDoc = parseN3Text(messageText, {
6034
+ baseIri: `${__sourceLabelToBaseIri(messageSourceLabel)}#message-${messageIndex}`,
6035
+ label: `${messageSourceLabel}#message-${messageIndex}`,
6036
+ keepSourceArtifacts: false,
6037
+ sourceLocations: false,
6038
+ rdf: false,
6039
+ });
6040
+ } catch (e) {
6041
+ if (e && e.name === 'N3SyntaxError') {
6042
+ console.error(formatN3SyntaxError(e, messageText, `${messageSourceLabel}#message-${messageIndex}`));
6043
+ process.exit(1);
6044
+ }
6045
+ throw e;
5948
6046
  }
5949
- throw e;
5950
- }
5951
6047
 
5952
- const merged = mergeParsedDocuments(programSources.concat([messageDoc]));
5953
- runParsedDocumentOnce(merged, { rdfMode, outputPrefixes: fullIriPrefixes });
5954
- });
5955
- } catch (e) {
5956
- console.error(`Error streaming RDF Message Log ${JSON.stringify(messageSourceLabel)}: ${e && e.message ? e.message : String(e)}`);
5957
- process.exit(1);
6048
+ const merged = mergeParsedDocuments(programSources.concat([messageDoc]));
6049
+ const result = runParsedDocumentOnce(merged, { rdfMode, outputPrefixes: fullIriPrefixes });
6050
+ if (store) pendingStoreWrites = pendingStoreWrites.then(() => persistRunResultToStore(store, result));
6051
+ });
6052
+ } catch (e) {
6053
+ console.error(`Error streaming RDF Message Log ${JSON.stringify(messageSourceLabel)}: ${e && e.message ? e.message : String(e)}`);
6054
+ process.exit(1);
6055
+ }
5958
6056
  }
6057
+ await pendingStoreWrites;
6058
+ } finally {
6059
+ if (store && typeof store.close === 'function') await store.close();
5959
6060
  }
5960
6061
  }
5961
6062
 
@@ -6091,10 +6192,6 @@ async function main() {
6091
6192
 
6092
6193
 
6093
6194
  if (streamMessagesMode) {
6094
- if (storeName) {
6095
- console.error('Error: --store cannot be combined with --stream-messages yet.');
6096
- process.exit(1);
6097
- }
6098
6195
  if (!rdfMode) {
6099
6196
  console.error('Error: --stream-messages requires -r/--rdf.');
6100
6197
  process.exit(1);
@@ -6130,17 +6227,94 @@ async function main() {
6130
6227
  }
6131
6228
  }
6132
6229
 
6133
- const sourceLabels = useImplicitStdin ? ['<stdin>'] : positional.map((item) => (item === '-' ? '<stdin>' : item));
6230
+ let sourceLabels = useImplicitStdin ? ['<stdin>'] : positional.map((item) => (item === '-' ? '<stdin>' : item));
6134
6231
  if (sourceLabels.filter((item) => item === '<stdin>').length > 1) {
6135
6232
  console.error('Error: stdin can only be used once.');
6136
6233
  process.exit(1);
6137
6234
  }
6138
6235
 
6139
6236
  if (streamMessagesMode) {
6140
- await runStreamMessagesMode(sourceLabels, { rdfMode });
6237
+ await runStreamMessagesMode(sourceLabels, { rdfMode, storeName, storePath, storeClear });
6141
6238
  return;
6142
6239
  }
6143
6240
 
6241
+ if (storeName && rdfMode) {
6242
+ const lineBasedSources = sourceLabels.filter(sourceLooksLikeLineBasedRdf);
6243
+ if (lineBasedSources.length) {
6244
+ if (showAst) {
6245
+ console.error('Error: line-based --store ingestion cannot be combined with --ast.');
6246
+ process.exit(1);
6247
+ }
6248
+ if (streamMode) {
6249
+ console.error('Error: line-based --store ingestion cannot be combined with --stream.');
6250
+ process.exit(1);
6251
+ }
6252
+ if (engine.getProofCommentsEnabled()) {
6253
+ console.error('Error: line-based --store ingestion currently does not support proof output.');
6254
+ process.exit(1);
6255
+ }
6256
+
6257
+ const store = await createCliStore({ storeName, storePath, storeClear });
6258
+ try {
6259
+ for (const sourceLabel of lineBasedSources) {
6260
+ try {
6261
+ await ingestLineBasedRdfSourceToStore(sourceLabel, store, { rdfMode });
6262
+ } catch (e) {
6263
+ console.error(`Error streaming RDF source ${JSON.stringify(sourceLabel)}: ${e && e.message ? e.message : String(e)}`);
6264
+ process.exit(1);
6265
+ }
6266
+ }
6267
+
6268
+ sourceLabels = sourceLabels.filter((sourceLabel) => !sourceLooksLikeLineBasedRdf(sourceLabel));
6269
+ if (!sourceLabels.length) return;
6270
+
6271
+ const parsedRuleSources = [];
6272
+ for (const sourceLabel of sourceLabels) {
6273
+ let text;
6274
+ try {
6275
+ text = __readInputSourceSync(sourceLabel);
6276
+ } catch (e) {
6277
+ if (sourceLabel === '<stdin>') console.error(`Error reading stdin: ${e.message}`);
6278
+ else console.error(`Error reading source ${JSON.stringify(sourceLabel)}: ${e.message}`);
6279
+ process.exit(1);
6280
+ }
6281
+
6282
+ try {
6283
+ parsedRuleSources.push(
6284
+ parseN3Text(text, {
6285
+ baseIri: __sourceLabelToBaseIri(sourceLabel),
6286
+ label: sourceLabel,
6287
+ collectUsedPrefixes: false,
6288
+ keepSourceArtifacts: false,
6289
+ sourceLocations: false,
6290
+ rdf: rdfMode,
6291
+ }),
6292
+ );
6293
+ } catch (e) {
6294
+ if (e && e.name === 'N3SyntaxError') {
6295
+ console.error(formatN3SyntaxError(e, text, sourceLabel));
6296
+ process.exit(1);
6297
+ }
6298
+ throw e;
6299
+ }
6300
+ }
6301
+
6302
+ const mergedRuleDocument = mergeParsedDocuments(parsedRuleSources);
6303
+ const result = await engine.runStoreBacked(mergedRuleDocument, store, { rdf: rdfMode });
6304
+ const outTriples = result.queryMode ? result.queryTriples || [] : (result.derived || []).map((df) => df.fact);
6305
+ if (result.queryMode) {
6306
+ const bodyText = engine.prettyPrintQueryTriples(outTriples, result.prefixes);
6307
+ if (bodyText) process.stdout.write(String(bodyText).replace(/\s*$/g, '') + '\n');
6308
+ } else {
6309
+ for (const tr of outTriples) console.log(engine.tripleToRdfCompatible(tr, result.prefixes));
6310
+ }
6311
+ return;
6312
+ } finally {
6313
+ if (store && typeof store.close === 'function') await store.close();
6314
+ }
6315
+ }
6316
+ }
6317
+
6144
6318
  const parsedSources = [];
6145
6319
  for (const sourceLabel of sourceLabels) {
6146
6320
  let text;
@@ -6997,7 +7171,7 @@ const trace = require('./trace');
6997
7171
  const { deterministicSkolemIdFromKey } = require('./skolem');
6998
7172
 
6999
7173
  const deref = require('./deref');
7000
- const { createFactStore, collectStore, MemoryFactStore, PersistentFactStore } = require('./store');
7174
+ const { createFactStore, collectStore, MemoryFactStore, PersistentFactStore, tripleToStoreKey } = require('./store');
7001
7175
 
7002
7176
  const hasOwn = Object.prototype.hasOwnProperty;
7003
7177
 
@@ -10704,6 +10878,164 @@ async function __parseRunAsyncInput(input, opts) {
10704
10878
  });
10705
10879
  }
10706
10880
 
10881
+ function __storePatternTerm(t, subst) {
10882
+ const applied = applySubstTerm(t, subst || __emptySubst());
10883
+ return containsVarTerm(applied) ? null : applied;
10884
+ }
10885
+
10886
+ function __mergeStoreSubst(base, delta) {
10887
+ let out = base;
10888
+ for (const k of Object.keys(delta || {})) {
10889
+ const v = delta[k];
10890
+ if (Object.prototype.hasOwnProperty.call(out, k)) {
10891
+ if (!termsEqual(out[k], v)) return null;
10892
+ } else {
10893
+ if (out === base) out = __cloneSubst(base);
10894
+ out[k] = v;
10895
+ }
10896
+ }
10897
+ return out;
10898
+ }
10899
+
10900
+ async function __proveGoalsAgainstStore(goals, subst, store, backRules, localFacts, depth, varGen, opts = {}) {
10901
+ if (!Array.isArray(goals) || goals.length === 0) return [subst || __emptySubst()];
10902
+ if (depth > 64) return [];
10903
+
10904
+ const goal0 = applySubstTriple(goals[0], subst || __emptySubst());
10905
+ const rest = goals.slice(1);
10906
+ const out = [];
10907
+
10908
+ if (isBuiltinPred(goal0.p)) {
10909
+ const deltas = evalBuiltin(goal0, __emptySubst(), localFacts || [], backRules || [], depth, varGen, undefined);
10910
+ for (const delta of deltas) {
10911
+ const nextSubst = __mergeStoreSubst(subst || __emptySubst(), delta);
10912
+ if (nextSubst === null) continue;
10913
+ out.push(...await __proveGoalsAgainstStore(rest, nextSubst, store, backRules, localFacts, depth + 1, varGen, opts));
10914
+ if (opts.maxResults && out.length >= opts.maxResults) return out.slice(0, opts.maxResults);
10915
+ }
10916
+ return out;
10917
+ }
10918
+
10919
+ // Backward rules are kept in memory; they may call back into the persistent
10920
+ // fact store for their own premises.
10921
+ if (goal0.p instanceof Iri && Array.isArray(backRules) && backRules.length) {
10922
+ ensureBackRuleIndexes(backRules);
10923
+ const candRules = (backRules.__byHeadPred.get(goal0.p.__tid) || []).concat(backRules.__wildHeadPred || []);
10924
+ for (const r of candRules) {
10925
+ if (!r || !Array.isArray(r.conclusion) || r.conclusion.length !== 1) continue;
10926
+ const rStd = standardizeRule(r, varGen);
10927
+ const head = rStd.conclusion[0];
10928
+ const s2 = unifyTriple(head, goal0, subst || __emptySubst());
10929
+ if (s2 === null) continue;
10930
+ const newGoals = (rStd.premise || []).concat(rest);
10931
+ out.push(...await __proveGoalsAgainstStore(newGoals, s2, store, backRules, localFacts, depth + 1, varGen, opts));
10932
+ if (opts.maxResults && out.length >= opts.maxResults) return out.slice(0, opts.maxResults);
10933
+ }
10934
+ }
10935
+
10936
+ const sPat = __storePatternTerm(goal0.s, subst || __emptySubst());
10937
+ const pPat = __storePatternTerm(goal0.p, subst || __emptySubst());
10938
+ const oPat = __storePatternTerm(goal0.o, subst || __emptySubst());
10939
+
10940
+ for await (const fact of store.match(sPat, pPat, oPat)) {
10941
+ const s2 = unifyTriple(goal0, fact, subst || __emptySubst());
10942
+ if (s2 === null) continue;
10943
+ out.push(...await __proveGoalsAgainstStore(rest, s2, store, backRules, localFacts, depth + 1, varGen, opts));
10944
+ if (opts.maxResults && out.length >= opts.maxResults) return out.slice(0, opts.maxResults);
10945
+ }
10946
+
10947
+ return out;
10948
+ }
10949
+
10950
+ async function runStoreBacked(input, store, opts = {}) {
10951
+ const parsed = parseN3SourceList(input, {
10952
+ baseIri: opts.baseIri || null,
10953
+ rdf: !!opts.rdf,
10954
+ sourceLocations: !!opts.proof,
10955
+ }) || input;
10956
+
10957
+ const prefixes = parsed.prefixes;
10958
+ const triples = parsed.triples || [];
10959
+ const frules = parsed.frules || [];
10960
+ const brules = parsed.brules || [];
10961
+ const qrules = parsed.logQueryRules || [];
10962
+
10963
+ materializeRdfLists(triples, frules.concat(qrules || []), brules);
10964
+ await store.batchAdd(triples, 'explicit');
10965
+
10966
+ const derived = [];
10967
+ const derivedKeys = new Set();
10968
+ const varGen = [0];
10969
+ const maxIterations = Number.isInteger(opts.maxIterations) && opts.maxIterations > 0 ? opts.maxIterations : 1024;
10970
+
10971
+ for (let iteration = 0; iteration < maxIterations; iteration += 1) {
10972
+ let changed = false;
10973
+ for (let ruleIndex = 0; ruleIndex < frules.length; ruleIndex += 1) {
10974
+ const r = frules[ruleIndex];
10975
+ if (!r || r.isFuse || r.__dynamicConclusionTerm) continue;
10976
+ __prepareForwardRule(r);
10977
+ const solutions = await __proveGoalsAgainstStore(r.premise || [], __emptySubst(), store, brules, triples, 0, varGen, {});
10978
+ for (const subst of solutions) {
10979
+ for (const cpat of r.conclusion || []) {
10980
+ const fact = applySubstTriple(cpat, subst);
10981
+ if (!isGroundTriple(fact)) continue;
10982
+ if (await store.add(fact, 'inferred')) {
10983
+ const df = makeDerivedRecord(fact, r, (r.premise || []).map((p) => applySubstTriple(p, subst)), subst, false);
10984
+ const key = tripleToStoreKey(fact);
10985
+ if (!derivedKeys.has(key)) {
10986
+ derivedKeys.add(key);
10987
+ derived.push(df);
10988
+ }
10989
+ changed = true;
10990
+ }
10991
+ }
10992
+ }
10993
+ }
10994
+ if (!changed) break;
10995
+ }
10996
+
10997
+ let queryTriples = [];
10998
+ const queryDerived = [];
10999
+ if (qrules.length) {
11000
+ for (const r of qrules) {
11001
+ const solutions = await __proveGoalsAgainstStore(r.premise || [], __emptySubst(), store, brules, triples, 0, varGen, {});
11002
+ for (const subst of solutions) {
11003
+ for (const cpat of r.conclusion || []) {
11004
+ const fact = applySubstTriple(cpat, subst);
11005
+ if (!isGroundTriple(fact)) continue;
11006
+ queryTriples.push(fact);
11007
+ queryDerived.push(makeDerivedRecord(fact, r, (r.premise || []).map((p) => applySubstTriple(p, subst)), subst, false));
11008
+ }
11009
+ }
11010
+ }
11011
+ }
11012
+
11013
+ if (queryTriples.length) {
11014
+ const seen = new Set();
11015
+ queryTriples = queryTriples.filter((tr) => {
11016
+ const key = tripleToStoreKey(tr);
11017
+ if (seen.has(key)) return false;
11018
+ seen.add(key);
11019
+ return true;
11020
+ });
11021
+ }
11022
+
11023
+ return {
11024
+ prefixes,
11025
+ facts: [],
11026
+ derived,
11027
+ queryMode: !!qrules.length,
11028
+ queryTriples,
11029
+ queryDerived,
11030
+ closureN3: qrules.length
11031
+ ? prettyPrintQueryTriples(queryTriples, prefixes)
11032
+ : derived.map((df) => (opts.rdf ? tripleToRdfCompatible(df.fact, prefixes) : tripleToN3(df.fact, prefixes))).join('\n'),
11033
+ store,
11034
+ storeBacked: true,
11035
+ };
11036
+ }
11037
+
11038
+
10707
11039
  function __withoutStoreOptions(opts) {
10708
11040
  const out = { ...(opts || {}) };
10709
11041
  delete out.store;
@@ -10898,6 +11230,7 @@ function setTracePrefixes(v) {
10898
11230
  module.exports = {
10899
11231
  reasonStream,
10900
11232
  runAsync,
11233
+ runStoreBacked,
10901
11234
  reasonRdfJs,
10902
11235
  collectLogQueryConclusions,
10903
11236
  forwardChainAndCollectLogQueryConclusions,
@@ -17705,7 +18038,10 @@ class ClassicLevelKv {
17705
18038
  const classic = __dynamicRequire('classic-level');
17706
18039
  const ClassicLevel = classic && (classic.ClassicLevel || classic.Level || classic.default);
17707
18040
  if (!ClassicLevel) throw new Error('classic-level is not installed');
17708
- this.db = new ClassicLevel(location, { valueEncoding: 'json' });
18041
+ const fs = __dynamicRequire('node:fs');
18042
+ const path = __dynamicRequire('node:path');
18043
+ if (fs && path) fs.mkdirSync(path.dirname(location), { recursive: true });
18044
+ this.db = new ClassicLevel(location, { valueEncoding: 'json', createIfMissing: true, errorIfExists: false });
17709
18045
  this.opened = false;
17710
18046
  }
17711
18047