Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plain, Star, Roles, Patterns and Generics #23

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 130 additions & 39 deletions data-model.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @see Literal
* @see Variable
* @see DefaultGraph
* @see Quad
* @see PlainQuad
*/
export type Term = NamedNode | BlankNode | Literal | Variable | DefaultGraph | BaseQuad;

Expand Down Expand Up @@ -58,7 +58,7 @@ export interface BlankNode {
/**
* An RDF literal, containing a string with an optional language tag and/or datatype.
*/
export interface Literal {
export interface Literal<Datatype extends StarRole.Datatype=StarRole.Datatype> {
/**
* Contains the constant "Literal".
*/
Expand All @@ -76,7 +76,7 @@ export interface Literal {
/**
* A NamedNode whose IRI represents the datatype of the literal.
*/
datatype: NamedNode;
datatype: Datatype;

/**
* @param other The term to compare with.
Expand Down Expand Up @@ -127,38 +127,86 @@ export interface DefaultGraph {
equals(other: Term | null | undefined): boolean;
}


/**
* The subject, which is a NamedNode, BlankNode or Variable.
* @see NamedNode
* @see BlankNode
* @see Variable
* Type to be unioned with term types for forming role-specific pattern types
*/
export type Quad_Subject = NamedNode | BlankNode | Quad | Variable;
export type TermPattern = Variable | null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also undefined?



/**
* The predicate, which is a NamedNode or Variable.
* @see NamedNode
* @see Variable
* Unions of Term types for the various roles they play in 'plain' RDF 1.1 Data
*/
export type Quad_Predicate = NamedNode | Variable;
export namespace PlainRole {
export type Subject = NamedNode | BlankNode;
export type Predicate = NamedNode;
export type Object = NamedNode | BlankNode | Literal<Datatype>;
export type Graph = DefaultGraph | NamedNode | BlankNode;
export type Datatype = NamedNode;
export type Quad = PlainQuad;
}

/**
* The object, which is a NamedNode, Literal, BlankNode or Variable.
* @see NamedNode
* @see Literal
* @see BlankNode
* @see Variable
* Unions of Term types for the various
*/
export type Quad_Object = NamedNode | Literal | BlankNode | Quad | Variable;
export namespace PlainPatern {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export namespace PlainPatern {
export namespace PlainPattern {

export type Subject = PlainRole.Subject | TermPattern;
export type Predicate = PlainRole.Predicate | TermPattern;
export type Object = PlainRole.Object | TermPattern;
export type Graph = PlainRole.Graph | TermPattern;
export type Datatype = PlainRole.Datatype | TermPattern;
export type Quad = PlainQuad | TermPattern;
}


/**
* The named graph, which is a DefaultGraph, NamedNode, BlankNode or Variable.
* @see DefaultGraph
* @see NamedNode
* @see BlankNode
* @see Variable
* Unions of Term types for the various roles they play in RDF-star data
*/
export type Quad_Graph = DefaultGraph | NamedNode | BlankNode | Variable;
export namespace StarRole {
export type Subject = PlainRole.Subject | StarQuad;
export type Predicate = PlainRole.Predicate;
export type Object = NamedNode | BlankNode | Literal<Datatype> | StarQuad;
export type Graph = PlainRole.Graph;
export type Datatype = PlainRole.Datatype;
export type Quad = StarQuad;
}

/**
* Unions of Term types for the various
*/
export namespace StarPatern {
export type Subject = StarRole.Subject | TermPattern;
export type Predicate = StarRole.Predicate | TermPattern;
export type Object = StarRole.Object | TermPattern;
export type Graph = StarRole.Graph | TermPattern;
export type Datatype = StarRole.Datatype | TermPattern;
export type Quad = StarQuad | TermPattern;
}


/**
* The subject, which is a NamedNode, BlankNode or Variable.
* @deprecated Consider using one of the following types instead: @see StarRole.Subject, @see StarPattern.Subject, @see PlainRole.Subject, or @see PlainPatern.Subject
*/
export type Quad_Subject = StarRole.Subject | Variable;

/**
* The predicate, which is a NamedNode or Variable.
* @deprecated Consider using one of the following types instead: @see StarRole.Predicate, @see StarPattern.Predicate, @see PlainRole.Predicate, or @see PlainPatern.Predicate
*/
export type Quad_Predicate = StarRole.Predicate | Variable;

/**
* The object, which is a NamedNode, Literal, BlankNode or Variable.
* @deprecated Consider using one of the following types instead: @see StarRole.Object, @see StarPattern.Object, @see PlainRole.Object, or @see PlainPatern.Object
*/
export type Quad_Object = StarRole.Object | Variable;

/**
* The named graph, which is a DefaultGraph, NamedNode, BlankNode or Variable.
* @deprecated Consider using one of the following types instead: @see StarRole.Graph, @see StarPattern.Graph, @see PlainRole.Graph, or @see PlainPatern.Graph
*/
export type Quad_Graph = StarRole.Graph | Variable;

/**
* An RDF quad, taking any Term in its positions, containing the subject, predicate, object and graph terms.
Expand All @@ -175,22 +223,18 @@ export interface BaseQuad {

/**
* The subject.
* @see Quad_Subject
*/
subject: Term;
/**
* The predicate.
* @see Quad_Predicate
*/
predicate: Term;
/**
* The object.
* @see Quad_Object
*/
object: Term;
/**
* The named graph.
* @see Quad_Graph
*/
graph: Term;

Expand All @@ -202,9 +246,9 @@ export interface BaseQuad {
}

/**
* An RDF quad, containing the subject, predicate, object and graph terms.
* @deprecated This interface allows for `Variable` term types in the quad components. Consider using either @see StarQuad or @see PlainQuad instead
*/
export interface Quad extends BaseQuad {
export interface Quad extends BaseQuad {
/**
* The subject.
* @see Quad_Subject
Expand All @@ -225,18 +269,65 @@ export interface Quad extends BaseQuad {
* @see Quad_Graph
*/
graph: Quad_Graph;
}

/**
* An RDF quad, containing the subject, predicate, object and graph terms.
*/
export interface StarQuad extends BaseQuad {
/**
* The subject.
* @see StarRole.Subject
*/
subject: StarRole.Subject;
/**
* The predicate.
* @see StarRole.Predicate
*/
predicate: StarRole.Predicate;
/**
* The object.
* @see StarRole.Object
*/
object: StarRole.Object;
/**
* The named graph.
* @see StarRole.Graph
*/
graph: StarRole.Graph;
}

/**
* An RDF quad, containing the subject, predicate, object and graph terms.
*/
export interface PlainQuad extends StarQuad {
/**
* @param other The term to compare with.
* @return True if and only if the argument is a) of the same type b) has all components equal.
* The subject.
* @see PlainRole.Subject
*/
equals(other: Term | null | undefined): boolean;
subject: PlainRole.Subject;
/**
* The predicate.
* @see PlainRole.Predicate
*/
predicate: PlainRole.Predicate;
/**
* The object.
* @see PlainRole.Object
*/
object: PlainRole.Object;
/**
* The named graph.
* @see PlainRole.Graph
*/
graph: PlainRole.Graph;
}


/**
* A factory for instantiating RDF terms and quads.
*/
export interface DataFactory<OutQuad extends BaseQuad = Quad, InQuad extends BaseQuad = OutQuad> {
export interface DataFactory<OutQuad extends BaseQuad = StarQuad, InQuad extends BaseQuad = StarQuad> {
/**
* @param value The IRI for the named node.
* @return A new instance of NamedNode.
Expand All @@ -256,10 +347,10 @@ export interface DataFactory<OutQuad extends BaseQuad = Quad, InQuad extends Bas
/**
* @param value The literal value.
* @param languageOrDatatype The optional language or datatype.
* If `languageOrDatatype` is a NamedNode,
* then it is used for the value of `NamedNode.datatype`.
* Otherwise `languageOrDatatype` is used for the value
* of `NamedNode.language`.
* If `languageOrDatatype` is a NamedNode,
* then it is used for the value of `NamedNode.datatype`.
* Otherwise `languageOrDatatype` is used for the value
* of `NamedNode.language`.
* @return A new instance of Literal.
* @see Literal
*/
Expand All @@ -284,7 +375,7 @@ export interface DataFactory<OutQuad extends BaseQuad = Quad, InQuad extends Bas
* @param object The quad object term.
* @param graph The quad graph term.
* @return A new instance of Quad.
* @see Quad
* @see PlainQuad
*/
quad(subject: InQuad['subject'], predicate: InQuad['predicate'], object: InQuad['object'], graph?: InQuad['graph']): OutQuad;
}
27 changes: 10 additions & 17 deletions dataset.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* Dataset Interfaces */
/* https://rdf.js.org/dataset-spec/ */

import { Quad, BaseQuad, Term } from './data-model';
import { BaseQuad, StarQuad, TermPattern } from './data-model';
import { Stream } from './stream';

export interface DatasetCore<OutQuad extends BaseQuad = Quad, InQuad extends BaseQuad = OutQuad> {

export interface DatasetCore<OutQuad extends BaseQuad = StarQuad, InQuad extends BaseQuad = StarQuad> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not agree with this change. I remember having discussed this with @bergos. While I agree with you goal to have the "in" type be more accepting so that any Term can be passed as argument, this does not reflect reality.

Implementations may or may not require their specific types being used. It is safer to default to a more strict pattern where same type is enforced. This way the author of library or type declaration has the choice to relax the default. It is as simple as

-export class MyDataset extends RDFJS.DatasetCore<MySpecialQuad> {
+export class MyDataset extends RDFJS.DatasetCore<MySpecialQuad, StarQuad> {
    // ...
}

The alternative is that consumers will use MyDataset unbeknownst that it will break in runtime when anything other that MySpecialQuad is provided.

/**
* A non-negative integer that specifies the number of quads in the set.
*/
Expand Down Expand Up @@ -42,19 +43,19 @@ export interface DatasetCore<OutQuad extends BaseQuad = Quad, InQuad extends Bas
* @param object The optional exact object to match.
* @param graph The optional exact graph to match.
*/
match(subject?: Term | null, predicate?: Term | null, object?: Term | null, graph?: Term | null): DatasetCore<OutQuad, InQuad>;
match(subject?: InQuad['subject'] | TermPattern, predicate?: InQuad['predicate'] | TermPattern, object?: InQuad['object'] | TermPattern, graph?: InQuad['graph'] | TermPattern): DatasetCore<OutQuad, InQuad>;

[Symbol.iterator](): Iterator<OutQuad>;
}

export interface DatasetCoreFactory<OutQuad extends BaseQuad = Quad, InQuad extends BaseQuad = OutQuad, D extends DatasetCore<OutQuad, InQuad> = DatasetCore<OutQuad, InQuad>> {
export interface DatasetCoreFactory<OutQuad extends BaseQuad = StarQuad, InQuad extends BaseQuad = StarQuad, D extends DatasetCore<OutQuad, InQuad> = DatasetCore<OutQuad, InQuad>> {
/**
* Returns a new dataset and imports all quads, if given.
*/
dataset(quads?: InQuad[]): D;
}

export interface Dataset<OutQuad extends BaseQuad = Quad, InQuad extends BaseQuad = OutQuad> extends DatasetCore<OutQuad, InQuad> {
export interface Dataset<OutQuad extends BaseQuad = StarQuad, InQuad extends BaseQuad = StarQuad> extends DatasetCore<OutQuad, InQuad> {
/**
* Imports the quads into this dataset.
*
Expand Down Expand Up @@ -82,7 +83,7 @@ export interface Dataset<OutQuad extends BaseQuad = Quad, InQuad extends BaseQua
* @param object The optional exact object to match.
* @param graph The optional exact graph to match.
*/
deleteMatches(subject?: Term, predicate?: Term, object?: Term, graph?: Term): this;
deleteMatches(subject?: InQuad['subject'] | TermPattern, predicate?: InQuad['predicate'] | TermPattern, object?: InQuad['object'] | TermPattern, graph?: InQuad['graph'] | TermPattern): this;

/**
* Returns a new dataset that contains all quads from the current dataset, not included in the given dataset.
Expand Down Expand Up @@ -160,14 +161,6 @@ export interface Dataset<OutQuad extends BaseQuad = Quad, InQuad extends BaseQua
*/
some(iteratee: (quad: OutQuad, dataset: this) => boolean): boolean;

/**
* Returns the set of quads within the dataset as a host language native sequence, for example an `Array` in
* ECMAScript-262.
*
* Since a `Dataset` is an unordered set, the order of the quads within the returned sequence is arbitrary.
*/
toArray(): OutQuad[];

/**
* Returns an N-Quads string representation of the dataset, preprocessed with
* {@link https://json-ld.github.io/normalization/spec/|RDF Dataset Normalization} algorithm.
Expand All @@ -192,13 +185,13 @@ export interface Dataset<OutQuad extends BaseQuad = Quad, InQuad extends BaseQua
*/
union(quads: Dataset<InQuad>): Dataset<OutQuad, InQuad>;

match(subject?: Term | null, predicate?: Term | null, object?: Term | null, graph?: Term | null): Dataset<OutQuad, InQuad>;
match(subject?: InQuad['subject'] | TermPattern, predicate?: InQuad['predicate'] | TermPattern, object?: InQuad['object'] | TermPattern, graph?: InQuad['graph'] | TermPattern): Dataset<OutQuad, InQuad>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change, excuse the pun, does not match the spec.

Regardless, narrowing the parameters to a subset of Term will be a breaking change whenever the inputs were not strictly typed to the more specific type

let term: Term

// this works now
// will fail when merged
dataset.match(term)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will also make TermPattern redundant?

Copy link
Contributor Author

@blake-regalia blake-regalia Jul 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change allows the implementor to narrow the subtype of Quad they will accept, for example in a dataset that does not support RDF-Star. I don't see what makes this incompatible with the spec. Isn't this related to what you said above?

Implementations may or may not require their specific types being used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I see how it can appear contradictory.

While the vectors of the changes are opposite, in both cases I think they risk breaking the current behaviour. As mentioned above, a Dataset accepts any term in the match and other methods. Making it more strict will inevitable break the type checks in many projects.

I thought that maybe your changes could work if instead the defaults for type arguments were

-OutQuad extends BaseQuad = Quad
+OutQuad extends BaseQuad = BaseQuad

Thus, defaulting to Term for all parameters. However, consider type DatasetExt = DatasetCore<QuadExt>. Same thing happens, that TypeScript will refuse to transpile when Term is used as argument but rdf-ext will happily ignore "wrong" terms...

}

export interface DatasetFactory<OutQuad extends BaseQuad = Quad, InQuad extends BaseQuad = OutQuad, D extends Dataset<OutQuad, InQuad> = Dataset<OutQuad, InQuad>>
export interface DatasetFactory<OutQuad extends BaseQuad = StarQuad, InQuad extends BaseQuad = StarQuad, D extends Dataset<OutQuad, InQuad> = Dataset<OutQuad, InQuad>>
extends DatasetCoreFactory<OutQuad, InQuad, D> {
/**
* Returns a new dataset and imports all quads, if given.
*/
dataset(quads?: Dataset<InQuad>|InQuad[]): D;
dataset(quads?: Dataset<InQuad> | InQuad[]): D;
}
Loading