meta-log-db
Version:
Native database package for Meta-Log (ProLog, DataLog, R5RS)
117 lines (102 loc) • 2.63 kB
text/typescript
import { Fact, DatalogQueryResult, DatalogRule, DatalogProgram } from '../types/index.js';
import { FixedPoint } from './fixed-point.js';
import { FactExtraction } from './fact-extraction.js';
/**
* DataLog Engine for Meta-Log Database
*/
export class DatalogEngine {
private facts: Fact[] = [];
private rules: DatalogRule[] = [];
/**
* Add facts to the database
*/
addFacts(facts: Fact[]): void {
this.facts.push(...facts);
}
/**
* Add a rule to the database
*/
addRule(rule: DatalogRule): void {
this.rules.push(rule);
}
/**
* Build DataLog program from rules
*/
buildProgram(rules: DatalogRule[]): DatalogProgram {
return {
rules: [...rules],
facts: [...this.facts]
};
}
/**
* Query the database
*/
async query(goal: string, program?: DatalogProgram): Promise<DatalogQueryResult> {
const targetProgram = program || this.buildProgram(this.rules);
// Compute fixed point
const allFacts = FixedPoint.compute(targetProgram);
// Match goal against facts
const parsedGoal = this.parseGoal(goal);
const matchingFacts = allFacts.filter(fact => {
if (fact.predicate !== parsedGoal.predicate) {
return false;
}
if (fact.args.length !== parsedGoal.args.length) {
return false;
}
// Match arguments (variables match anything)
for (let i = 0; i < fact.args.length; i++) {
const goalArg = parsedGoal.args[i];
if (!goalArg.startsWith('?') && goalArg !== fact.args[i].toString()) {
return false;
}
}
return true;
});
return { facts: matchingFacts };
}
/**
* Compute fixed point
*/
fixedPoint(program: DatalogProgram): Fact[] {
return FixedPoint.compute(program);
}
/**
* Extract facts from canvas objects
*/
extractFacts(objects: any[]): Fact[] {
return FactExtraction.extractFromCanvas(objects);
}
/**
* Parse goal string
*/
private parseGoal(goal: string): { predicate: string; args: string[] } {
const match = goal.match(/^(\w+)\((.*)\)$/);
if (match) {
const predicate = match[1];
const argsStr = match[2];
const args = argsStr ? argsStr.split(',').map(s => s.trim()) : [];
return { predicate, args };
}
return { predicate: goal, args: [] };
}
/**
* Get all facts
*/
getFacts(): Fact[] {
return [...this.facts];
}
/**
* Get all rules
*/
getRules(): DatalogRule[] {
return [...this.rules];
}
/**
* Clear database
*/
clear(): void {
this.facts = [];
this.rules = [];
}
}