UNPKG

meta-log-db

Version:

Native database package for Meta-Log (ProLog, DataLog, R5RS)

212 lines (182 loc) 5.71 kB
import { RdfTriple, TriplePattern, SparqlQueryResult } from '../types/index.js'; import { SparqlParser } from './sparql-parser.js'; import { SparqlExecutor } from './sparql-executor.js'; /** * RDF Triple Store */ export class TripleStore { private triples: RdfTriple[] = []; private queryCache: Map<string, any> = new Map(); private cacheEnabled: boolean = true; /** * Add triples to the store */ addTriples(triples: RdfTriple[]): void { this.triples.push(...triples); } /** * Query triples by pattern */ query(pattern: TriplePattern): RdfTriple[] { return this.triples.filter(triple => { if (pattern.subject && triple.subject !== pattern.subject) { return false; } if (pattern.predicate && triple.predicate !== pattern.predicate) { return false; } if (pattern.object) { const objStr = typeof triple.object === 'string' ? triple.object : triple.object.value; if (objStr !== pattern.object) { return false; } } return true; }); } /** * Execute SPARQL query (enhanced implementation) * Supports: SELECT, DISTINCT, ORDER BY, LIMIT, OFFSET, FILTER, OPTIONAL */ async sparql(query: string): Promise<SparqlQueryResult> { // Check cache if (this.cacheEnabled) { const cached = this.queryCache.get(query); if (cached) { return cached; } } try { // Parse query using enhanced parser const parsedQuery = SparqlParser.parse(query); // Execute query using enhanced executor const executor = new SparqlExecutor(this.triples); const result = await executor.execute(parsedQuery); // Cache result if (this.cacheEnabled) { this.queryCache.set(query, result); } return result; } catch (error) { // Fallback to simplified parser for backward compatibility return this.sparqlSimple(query); } } /** * Simple SPARQL query execution (backward compatibility) */ private async sparqlSimple(query: string): Promise<SparqlQueryResult> { // Simple SELECT query parser const selectMatch = query.match(/SELECT\s+(.*?)\s+WHERE/i); if (!selectMatch) { throw new Error('Unsupported SPARQL query format'); } const variables = selectMatch[1].split(/\s+/).filter(v => v.startsWith('?')); // Extract WHERE clause patterns const whereMatch = query.match(/WHERE\s*\{([^}]+)\}/is); if (!whereMatch) { return { results: { bindings: [] } }; } const patterns = this.parseSparqlPatterns(whereMatch[1]); const bindings: Record<string, { value: string; type: string }>[] = []; // Simple pattern matching for (const pattern of patterns) { const matches = this.query(pattern); for (const match of matches) { const binding: Record<string, { value: string; type: string }> = {}; if (pattern.subject?.startsWith('?')) { binding[pattern.subject] = { value: match.subject, type: 'uri' }; } if (pattern.predicate?.startsWith('?')) { binding[pattern.predicate] = { value: match.predicate, type: 'uri' }; } if (pattern.object?.startsWith('?')) { const objValue = typeof match.object === 'string' ? match.object : match.object.value; binding[pattern.object] = { value: objValue, type: 'uri' }; } bindings.push(binding); } } return { results: { bindings } }; } /** * Enable/disable query caching */ setCacheEnabled(enabled: boolean): void { this.cacheEnabled = enabled; if (!enabled) { this.queryCache.clear(); } } /** * Clear query cache */ clearCache(): void { this.queryCache.clear(); } /** * Parse SPARQL patterns from WHERE clause */ private parseSparqlPatterns(whereClause: string): TriplePattern[] { const patterns: TriplePattern[] = []; const lines = whereClause.split('\n').map(l => l.trim()).filter(l => l); for (const line of lines) { const match = line.match(/(\S+)\s+(\S+)\s+(\S+)\s*\./); if (match) { patterns.push({ subject: match[1], predicate: match[2], object: match[3] }); } } return patterns; } /** * RDFS entailment (simplified) */ rdfsEntailment(triples: RdfTriple[]): RdfTriple[] { const entailed: RdfTriple[] = [...triples]; const rdfType = '<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>'; const rdfsSubClassOf = '<http://www.w3.org/2000/01/rdf-schema#subClassOf>'; // Find subClassOf relationships const subClassTriples = triples.filter(t => t.predicate === rdfsSubClassOf ); // Apply subClassOf transitivity for (const subClassTriple of subClassTriples) { const subClass = subClassTriple.subject; const superClass = typeof subClassTriple.object === 'string' ? subClassTriple.object : subClassTriple.object.value; // Find all instances of subClass const instances = triples.filter(t => t.predicate === rdfType && (typeof t.object === 'string' ? t.object : t.object.value) === subClass ); // Add type assertions for superClass for (const instance of instances) { entailed.push({ subject: instance.subject, predicate: rdfType, object: superClass }); } } return entailed; } /** * Get all triples */ getTriples(): RdfTriple[] { return [...this.triples]; } /** * Clear all triples */ clear(): void { this.triples = []; } }