import type { EventEmitter } from 'node:events'; import type * as RDF from '@rdfjs/types'; import type { AsyncIterator } from 'asynciterator'; import type { QuadTermName } from 'rdf-terms'; import { DatasetCoreWrapper } from './dataset/DatasetCoreWrapper'; import type { ITermDictionary } from './dictionary/ITermDictionary'; import type { IRdfStoreIndex } from './index/IRdfStoreIndex'; import type { IRdfStoreOptions } from './IRdfStoreOptions'; /** * An RDF store allows quads to be stored and fetched, based on one or more customizable indexes. */ export declare class RdfStore implements RDF.Store { static readonly DEFAULT_INDEX_COMBINATIONS: QuadTermName[][]; readonly options: IRdfStoreOptions; readonly dataFactory: RDF.DataFactory; readonly dictionary: ITermDictionary; readonly indexesWrapped: IRdfStoreIndexWrapped[]; private readonly indexesWrappedComponentOrders; readonly features: { quotedTripleFiltering: boolean; indexNodes: boolean; indexDistinctTerms: boolean; }; private readonly indexNodes; /** * Whether or not the dictionary and all indexes support quoted triple patterns. * This is invariant for the lifetime of the store, so it is determined once upon construction. */ private readonly indexesSupportQuotedPatterns; /** * Lookup table from a bitmask of defined quad pattern components to the best index. */ private readonly bestIndexLookup; /** * If every index can insert a batch of quads at once, in which case imports are batched. */ private readonly batchable; private _size; constructor(options: IRdfStoreOptions); /** * Create an RDF store whose indexes keep their quads sorted, so that scans produce ordered results * and can skip ahead. Stores quads in GSPO, GPOS, and GOSP order by default, like * {@link RdfStore#createDefault}. * @param options Optional settings. * @param options.termComparator The order to keep terms in, which defaults to {@link defaultTermComparator}. * @param options.indexCombinations The component orders of the indexes to create. * @param options.nodes If an index of nodes (subjects or objects) must be maintained. */ static createOrdered(options?: { termComparator?: (left: RDF.Term, right: RDF.Term) => number; indexCombinations?: QuadTermName[][]; nodes?: true; }): RdfStore; /** * Create an RDF store with default settings. * Concretely, this store stores triples in GSPO, GPOS, and GOSP order, * and makes use of in-memory number dictionary encoding. * @param nodes If an index of nodes (subjects or objects) must be maintained. */ static createDefault(nodes?: true): RdfStore; /** * Internal helper to create index objects. * @param options The RDF store options object. */ static constructIndexesWrapped(options: IRdfStoreOptions): IRdfStoreIndexWrapped[]; /** * Check if a given quad term order is valid. * @param combination A quad term order. */ static isCombinationValid(combination: QuadTermName[]): boolean; /** * Every order a scan of this store could come back in, one per index, as component names. * * A consumer that wants results in a particular order has to know whether this store can produce it * before it plans around one. The order a given pattern actually gets is the entry for the index that * serves it, with the components the pattern binds removed, since those do not vary across the scan. * * Only ordered indexes, such as {@link RdfStoreIndexBTree}, are listed: the others iterate in insertion * order, so a scan of them has no useful order at all. */ get indexOrders(): QuadTermName[][]; /** * The components a scan of the given index varies over, in the order it will produce them. * * Components fixed by the pattern are constant across the scan and therefore left out. Only * reported for an ordered index, since an unordered one produces no useful order. * @param index The index being scanned. * @param componentOrder The component order of the index being scanned. * @param subject The subject of the pattern. * @param predicate The predicate of the pattern. * @param object The object of the pattern. * @param graph The graph of the pattern. */ private resultOrderOf; /** * Build the callback that lets a scan skip ahead to a term, or undefined when it cannot. * * Skipping is only sound on an ordered index. * @param index The index being scanned. * @param componentOrder The component order of that index. * @param producer The producer reading that index. */ private createSeeker; /** * The number of quads in this store. */ get size(): number; /** * Add a quad to the store. * @param quad An RDF quad. * @return boolean If the quad was not yet present in the index. */ addQuad(quad: TQ): boolean; /** * Remove a quad from the store. * @param quad An RDF quad. * @return boolean If the quad was present in the index. */ removeQuad(quad: TQ): boolean; /** * Removes all streamed quads. * @param stream A stream of quads */ remove(stream: RDF.Stream): EventEmitter; /** * All quads matching the pattern will be removed. * @param subject The optional subject. * @param predicate The optional predicate. * @param object The optional object. * @param graph The optional graph. */ removeMatches(subject?: RDF.Term | null | undefined, predicate?: RDF.Term | null | undefined, object?: RDF.Term | null | undefined, graph?: RDF.Term | null | undefined): EventEmitter; /** * Deletes the given named graph. * @param graph The graph term or string to match. */ deleteGraph(graph: string | TQ['graph']): EventEmitter; /** * Import the given stream of quads into the store. * @param stream A stream of RDF quads. */ import(stream: RDF.Stream): EventEmitter; /** * Add many quads at once. * * If every index supports it, the quads are inserted as a single batch, which sorts them once per * index rather than inserting them one by one. Otherwise, this is the same as adding them one by one. * @param quads RDF quads. * @return number The number of quads that were not yet present. */ addQuads(quads: Iterable): number; private encodeInto; /** * Insert a batch of encoded quads into every index. * @param buffer Encoded quads in SPOG order, four entries per quad. * @param count The number of quads in the buffer. * @return number The number of quads that were not yet present. */ private addEncodedQuads; /** * Determine the best index for the given quad pattern. * * The best index only depends on which of the four components are defined, * so this is a lookup in a table that was precomputed upon construction. * * @param quadComponents A quad pattern. */ private getBestIndexWrapped; /** * Returns a generator producing all quads matching the pattern. * @param subject The optional subject. * @param predicate The optional predicate. * @param object The optional object. * @param graph The optional graph. */ readQuads(subject?: RDF.Term | null, predicate?: RDF.Term | null, object?: RDF.Term | null, graph?: RDF.Term | null): IterableIterator; /** * Returns an array containing all quads matching the pattern. * @param subject The optional subject. * @param predicate The optional predicate. * @param object The optional object. * @param graph The optional graph. */ getQuads(subject?: RDF.Term | null, predicate?: RDF.Term | null, object?: RDF.Term | null, graph?: RDF.Term | null): TQ[]; /** * Returns a stream that produces all quads matching the pattern. * @param subject The optional subject. * @param predicate The optional predicate. * @param object The optional object. * @param graph The optional graph. */ match(subject?: RDF.Term | null, predicate?: RDF.Term | null, object?: RDF.Term | null, graph?: RDF.Term | null): RDF.Stream & AsyncIterator; /** * Prepare the production of bindings for the given quad pattern. * * This determines the best index, encodes the pattern, works out which components must be * bound, and detects whether any post-filtering is required. * All of this only depends on the pattern, so it is done once per lookup instead of per result. * * @param bindingsFactory The factory to use for creating bindings. * @param subject The subject, which can be a variable. * @param predicate The predicate, which can be a variable. * @param object The object, which can be a variable. * @param graph The graph, which can be a variable. * @return A producer of bindings, or undefined if the pattern can not produce any results. */ private prepareBindings; /** * Returns a generator producing all quads matching the pattern. * @param bindingsFactory The factory to use for creating bindings. * @param subject The subject, which can be a variable. * @param predicate The predicate, which can be a variable. * @param object The object, which can be a variable. * @param graph The graph, which can be a variable. */ readBindings(bindingsFactory: RDF.BindingsFactory, subject: RDF.Term, predicate: RDF.Term, object: RDF.Term, graph: RDF.Term): IterableIterator; /** * Returns an array containing all bindings matching the pattern. * @param bindingsFactory The factory that will be used to create bindings. * @param subject The subject, which can be a variable. * @param predicate The predicate, which can be a variable. * @param object The object, which can be a variable. * @param graph The graph, which can be a variable. */ getBindings(bindingsFactory: RDF.BindingsFactory, subject: RDF.Term, predicate: RDF.Term, object: RDF.Term, graph: RDF.Term): RDF.Bindings[]; /** * Returns a stream that produces all quads matching the pattern. * @param bindingsFactory The factory that will be used to create bindings. * @param subject The subject, which can be a variable. * @param predicate The predicate, which can be a variable. * @param object The object, which can be a variable. * @param graph The graph, which can be a variable. */ matchBindings(bindingsFactory: RDF.BindingsFactory, subject: RDF.Term, predicate: RDF.Term, object: RDF.Term, graph: RDF.Term): AsyncIterator; /** * Returns the number of distinct terms that exist in the store. * * @param terms An array of quad term names * @param filters An optional array of quad components that must be matched. */ countDistinctTerms(terms: QuadTermName[], filters?: (RDF.Term | undefined)[]): number; /** * Returns a generator producing distinct arrays of terms that exist in the store. * Each returned array corresponds to the terms specified by given quad term names. * * For example, when requesting the terms `[ 'subject', 'predicate' ]`, * a produced array could be `[ 'ex:s', 'ex:p' ]`, * * For example, if filters is in the form of `[ undefined, DF.namedNode('ex:p'), undefined, DF.defaultGraph() ]`, * this means that only those distinct terms must be returned if they originate from quads with predicate 'ex:p' * and in the default graph. * * @param terms An array of quad term names * @param filters An optional array of quad components that must be matched. */ readDistinctTerms(terms: QuadTermName[], filters?: (RDF.Term | undefined)[]): IterableIterator; /** * Returns an array with distinct arrays of terms that exist in the store. * Each returned array corresponds to the terms specified by given quad term names. * * For example, when requesting the terms `[ 'subject', 'predicate' ]`, * a produced array could be `[ 'ex:s', 'ex:p' ]`, * * For example, if filters is in the form of `[ undefined, DF.namedNode('ex:p'), undefined, DF.defaultGraph() ]`, * this means that only those distinct terms must be returned if they originate from quads with predicate 'ex:p' * and in the default graph. * * @param terms An array of quad term names * @param filters An optional array of quad components that must be matched. */ getDistinctTerms(terms: QuadTermName[], filters?: (RDF.Term | undefined)[]): RDF.Term[][]; /** * Returns a stream with distinct arrays of terms that exist in the store. * Each returned array corresponds to the terms specified by given quad term names. * * For example, when requesting the terms `[ 'subject', 'predicate' ]`, * a produced array could be `[ 'ex:s', 'ex:p' ]`, * * For example, if filters is in the form of `[ undefined, DF.namedNode('ex:p'), undefined, DF.defaultGraph() ]`, * this means that only those distinct terms must be returned if they originate from quads with predicate 'ex:p' * and in the default graph. * * @param terms An array of quad term names * @param filters An optional array of quad components that must be matched. */ matchDistinctTerms(terms: QuadTermName[], filters?: (RDF.Term | undefined)[]): AsyncIterator; /** * Returns the number of nodes in the given graph (can be a variable). * Nodes are all terms that are either a subject or object within the store. * * This method can only be called when the store is constructed with `indexNodes: true`. */ countNodes(graph: RDF.Term): number; /** * Returns a generator producing all nodes in the given graph (can be a variable). * Nodes are all terms that are either a subject or object within the store. * * This method can only be called when the store is constructed with `indexNodes: true`. * * @param graph The graph to read the nodes from, or a variable if all graphs need to be considered. * * @returns a generator of tuples containing the named graph as first element and the node term as second element. */ readNodes(graph: RDF.Term): IterableIterator<[RDF.Term, RDF.Term]>; /** * Returns an array containing all nodes in the given graph (can be a variable). * Nodes are all terms that are either a subject or object within the store. * * This method can only be called when the store is constructed with `indexNodes: true`. * * @param graph The graph to read the nodes from, or a variable if all graphs need to be considered. * * @returns an array of tuples containing the named graph as first element and the node term as second element. */ getNodes(graph: RDF.Term): [RDF.Term, RDF.Term][]; /** * Returns a stream containing all nodes in the given graph (can be a variable). * Nodes are all terms that are either a subject or object within the store. * * This method can only be called when the store is constructed with `indexNodes: true`. * * @param graph The graph to read the nodes from, or a variable if all graphs need to be considered. * * @returns a stream of tuples containing the named graph as first element and the node term as second element. */ matchNodes(graph: RDF.Term): AsyncIterator<[RDF.Term, RDF.Term]>; /** * Returns the exact cardinality of the quads matching the pattern. * @param subject The optional subject. * @param predicate The optional predicate. * @param object The optional object. * @param graph The optional graph. */ countQuads(subject?: RDF.Term | null, predicate?: RDF.Term | null, object?: RDF.Term | null, graph?: RDF.Term | null): number; /** * Wrap this store inside a DatasetCore interface. * Any mutations in either this store or the wrapper will propagate to each other. */ asDataset(): DatasetCoreWrapper; } export interface IRdfStoreIndexWrapped { componentOrder: QuadTermName[]; /** * The precomputed permutation of SPOG indexes corresponding to `componentOrder`. */ componentOrderPermutation: number[]; componentOrderInverse: Record; index: IRdfStoreIndex; }