Skip to content

feat: add QuadPattern types for matching inside triple terms - #73

Draft
jeswr wants to merge 1 commit into
rdfjs:masterfrom
jeswr:feat/quad-patterns
Draft

jeswr wants to merge 1 commit into
rdfjs:masterfrom
jeswr:feat/quad-patterns

Conversation

@jeswr

@jeswr jeswr commented Oct 4, 2026

Copy link
Copy Markdown
Member

Requested by Jesse · project thread

Opened by Claude on behalf of Jesse as a draft. It is waiting for Jesse's review and is open for discussion. We're looking for input and consensus so that we can update the types.

Proposes types for #68 (matching patterns inside quads), using arrays for the patterns instead of Variable components.

Before: match takes terms or null, and a Quad passed to it only matches exactly, so there is no way to ask for every reifier of a triple term with a given subject without scanning.

After: two new types and one optional interface.

export type QuadPattern = readonly [subject?: TermPattern, predicate?: TermPattern, object?: TermPattern, graph?: TermPattern];
export type TermPattern = Term | QuadPattern | null | undefined;

export interface QuadPatternDatasetCore<OutQuad, InQuad> extends DatasetCore<OutQuad, InQuad> {
    match(subject?: TermPattern, predicate?: Term | null, object?: TermPattern, graph?: TermPattern): QuadPatternDatasetCore<OutQuad, InQuad>;
}

An array in the subject, object or graph position matches triple terms by their components: a missing, null or undefined entry matches anything, a term must be equal, and nested arrays recurse. dataset.match(null, rdf.reifies, [s, null, null]) finds every reifier of a triple term with subject s. The predicate stays Term | null, since a predicate cannot be a triple term.

Why arrays rather than Variables inside a Quad: a Quad whose components are Variables is already a valid term with exact-match meaning today, so giving it wildcard meaning in match would change what existing calls return. An array is not a term, so no existing call can pass one, and its meaning can be defined without touching Quad.equals or Variable (see the concerns in rdfjs/data-model-spec#162). Joins over repeated variables stay with a bindings-level API such as #71.

Compatibility: purely additive. DatasetCore is unchanged, so existing implementations and callers compile and behave as before, and datasets without triple-term indexes need not do anything. A dataset opts in by implementing QuadPatternDatasetCore, which is still assignable to DatasetCore. npm test and npm run lint pass (lint reports only the warnings already on master).

Open questions:

  1. Should the same patterns be allowed on Source.match and Dataset.deleteMatches?
  2. Should a separate name be found for the interface, or should a later major version fold the wider match into DatasetCore itself?
  3. Should a missing graph entry mean "any graph" (as here, and in N3.js's implementation) or "default graph"?

Implementation and benchmarks: rdfjs/N3.js#811 (O(matches) lookups at 1 M quads, about 180 µs against 850 ms for a scan). That work is moving to n3-match-bgp while this is discussed: jeswr/n3-match-bgp#1

🤖 Generated with Claude Code

https://claude.ai/code/session_016PTUEUKZE6DwmyBQbpLa9T

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PTUEUKZE6DwmyBQbpLa9T
@changeset-bot

changeset-bot Bot commented Oct 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cd6e76c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@rdfjs/types Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants