Skip to content

Commit 4acc662

Browse files
committed
What if TermWrapper extends Term?
1 parent 7b8a07c commit 4acc662

File tree

10 files changed

+124
-60
lines changed

10 files changed

+124
-60
lines changed

src/ListItem.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class ListItem<T> extends TermWrapper {
3232
}
3333

3434
public get isNil(): boolean {
35-
return this.term.equals(this.factory.namedNode(RDF.nil))
35+
return this.equals(this.factory.namedNode(RDF.nil))
3636
}
3737

3838
public get first(): T {
@@ -44,7 +44,7 @@ export class ListItem<T> extends TermWrapper {
4444
}
4545

4646
public get rest(): ListItem<T> {
47-
return this.singular(RDF.rest, w => new ListItem(w.term, w.dataset, w.factory, this.valueMapping, this.termMapping))
47+
return this.singular(RDF.rest, w => new ListItem(w as Term, w.dataset, w.factory, this.valueMapping, this.termMapping))
4848
}
4949

5050
public set rest(value: ListItem<T>) {

src/Overwriter.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { TermWrapper } from "./TermWrapper.js"
22
import { ListItem } from "./ListItem.js"
33
import { TermMapping } from "./mapping/TermMapping.js"
4+
import type { Term } from "@rdfjs/types"
45

56
export class Overwriter<T> extends TermWrapper {
6-
constructor(subject: TermWrapper, private readonly predicate: string) {
7-
super(subject.term, subject.dataset, subject.factory);
7+
constructor(subject: TermWrapper, private readonly p: string) {
8+
super(subject as Term, subject.dataset, subject.factory);
89
}
910

1011
set listNode(object: ListItem<T>) {
11-
this.overwrite(this.predicate, object, TermMapping.identity)
12+
this.overwrite(this.p, object, TermMapping.identity)
1213
}
1314
}

src/TermWrapper.ts

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,25 @@
1-
import type { DataFactory, DatasetCore, Quad_Object, Quad_Subject, Term } from "@rdfjs/types"
1+
import type { Quad_Object, Quad_Subject, Term } from "@rdfjs/types"
22
import type { ITermMapping } from "./type/ITermMapping.js"
33
import type { IValueMapping } from "./type/IValueMapping.js"
44
import { WrappingSet } from "./WrappingSet.js"
55
import { WrappingMap } from "./WrappingMap.js"
6+
import { Something } from "./something.js"
67

78

8-
export class TermWrapper {
9-
public readonly term: Term;
10-
public readonly dataset: DatasetCore;
11-
public readonly factory: DataFactory;
12-
13-
public constructor(term: string, dataset: DatasetCore, factory: DataFactory);
14-
public constructor(term: Term, dataset: DatasetCore, factory: DataFactory);
15-
public constructor(term: string | Term, dataset: DatasetCore, factory: DataFactory) {
16-
if (typeof term === "string") {
17-
this.term = factory.namedNode(term);
18-
} else {
19-
this.term = term;
20-
}
21-
this.dataset = dataset;
22-
this.factory = factory;
23-
}
24-
9+
export class TermWrapper extends Something {
2510
protected singular<T>(p: string, valueMapping: IValueMapping<T>): T {
2611
const predicate = this.factory.namedNode(p)
27-
const matches = this.dataset.match(this.term, predicate)[Symbol.iterator]()
12+
const matches = this.dataset.match(this as Term, predicate)[Symbol.iterator]()
2813

2914
// TODO: Expose standard errors
3015
const {value: first, done: none} = matches.next()
3116

3217
if (none) {
33-
throw new Error(`More than one value for predicate ${p} on term ${this.term.value}`)
18+
throw new Error(`More than one value for predicate ${p} on term ${this.value}`)
3419
}
3520

3621
if (!matches.next().done) {
37-
throw new Error(`No value found for predicate ${p} on term ${this.term.value}`)
22+
throw new Error(`No value found for predicate ${p} on term ${this.value}`)
3823
}
3924

4025
return valueMapping(new TermWrapper(first.object, this.dataset, this.factory))
@@ -43,7 +28,7 @@ export class TermWrapper {
4328
protected singularNullable<T>(p: string, valueMapping: IValueMapping<T>): T | undefined {
4429
const predicate = this.factory.namedNode(p)
4530

46-
for (const q of this.dataset.match(this.term, predicate)) {
31+
for (const q of this.dataset.match(this as Term, predicate)) {
4732
return valueMapping(new TermWrapper(q.object, this.dataset, this.factory))
4833
}
4934

@@ -61,7 +46,7 @@ export class TermWrapper {
6146
protected overwriteNullable<T>(p: string, value: T | undefined, termMapping: ITermMapping<T>): void {
6247
const predicate = this.factory.namedNode(p)
6348

64-
for (const q of this.dataset.match(this.term, predicate)) {
49+
for (const q of this.dataset.match(this as Term, predicate)) {
6550
this.dataset.delete(q)
6651
}
6752

@@ -70,9 +55,9 @@ export class TermWrapper {
7055
return
7156
}
7257

73-
// TODO: Do we really need to test if this.term is a Quad Subject here?
58+
// TODO: Do we really need to test if this is a Quad Subject here?
7459
// @Samu I imagine this is tested at instantiation time in the constructor if at all
75-
if (!TermWrapper.isQuadSubject(this.term)) {
60+
if (!TermWrapper.isQuadSubject(this as Term)) {
7661
return // TODO: throw error?
7762
}
7863

@@ -83,11 +68,11 @@ export class TermWrapper {
8368
return // TODO: throw error?
8469
}
8570

86-
if (!TermWrapper.isQuadObject(o.term)) {
71+
if (!TermWrapper.isQuadObject(o as Term)) {
8772
return // TODO: throw error?
8873
}
8974

90-
const q = this.factory.quad(this.term, predicate, o.term)
75+
const q = this.factory.quad(this as Quad_Subject, predicate, o as Quad_Object)
9176
this.dataset.add(q)
9277
}
9378

src/WrappingMap.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { TermWrapper } from "./TermWrapper.js"
22
import type { IValueMapping } from "./type/IValueMapping.js"
33
import type { ITermMapping } from "./type/ITermMapping.js"
4-
import type { Quad, Quad_Object, Quad_Subject } from "@rdfjs/types"
4+
import type { Quad, Quad_Object, Quad_Subject, Term } from "@rdfjs/types"
55

66
export class WrappingMap<TKey, TValue> implements Map<TKey, TValue> {
77
constructor(private readonly subject: TermWrapper, private readonly predicate: string, private readonly valueMapping: IValueMapping<[TKey, TValue]>, private readonly termMapping: ITermMapping<[TKey, TValue]>) {
@@ -23,9 +23,9 @@ export class WrappingMap<TKey, TValue> implements Map<TKey, TValue> {
2323

2424
this.subject.dataset.delete(
2525
this.subject.factory.quad(
26-
this.subject.term as Quad_Subject,
26+
this.subject as Quad_Subject,
2727
p,
28-
this.termMapping(entry, this.subject.dataset, this.subject.factory)!.term as Quad_Object))
28+
this.termMapping(entry, this.subject.dataset, this.subject.factory) as Quad_Object))
2929

3030
return true
3131
}
@@ -99,16 +99,16 @@ export class WrappingMap<TKey, TValue> implements Map<TKey, TValue> {
9999
private get matches(): Iterable<Quad> {
100100
const p = this.subject.factory.namedNode(this.predicate)
101101

102-
return this.subject.dataset.match(this.subject.term, p)
102+
return this.subject.dataset.match(this.subject as Term, p)
103103
}
104104

105105
private add(k: TKey, v: TValue) {
106106
const p = this.subject.factory.namedNode(this.predicate)
107107

108108
this.subject.dataset.add(
109109
this.subject.factory.quad(
110-
this.subject.term as Quad_Subject,
110+
this.subject as Quad_Subject,
111111
p,
112-
this.termMapping([k, v], this.subject.dataset, this.subject.factory)!.term as Quad_Object))
112+
this.termMapping([k, v], this.subject.dataset, this.subject.factory) as Quad_Object))
113113
}
114114
}

src/WrappingSet.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { IValueMapping } from "./type/IValueMapping.js"
22
import type { ITermMapping } from "./type/ITermMapping.js"
3-
import type { DatasetCore, Quad, Quad_Object, Quad_Subject } from "@rdfjs/types"
3+
import type { DatasetCore, Quad, Quad_Object, Quad_Subject, Term } from "@rdfjs/types"
44
import { TermWrapper } from "./TermWrapper.js"
55

66
export class WrappingSet<T> implements Set<T> {
@@ -24,10 +24,10 @@ export class WrappingSet<T> implements Set<T> {
2424
return false
2525
}
2626

27-
const o = this.termMapping(value, this.subject.dataset, this.subject.factory)?.term // TODO: guards
27+
const o = this.termMapping(value, this.subject.dataset, this.subject.factory) // TODO: guards
2828
const p = this.subject.factory.namedNode(this.predicate)
2929

30-
for (const q of this.subject.dataset.match(this.subject.term, p, o)) {
30+
for (const q of this.subject.dataset.match(this.subject as Term, p, o as Term)) {
3131
this.subject.dataset.delete(q)
3232
}
3333

@@ -73,15 +73,15 @@ export class WrappingSet<T> implements Set<T> {
7373
}
7474

7575
private quad(value: T): Quad {
76-
const s = this.subject.term as Quad_Subject // TODO: guard
76+
const s = this.subject as Quad_Subject // TODO: guard
7777
const p = this.subject.factory.namedNode(this.predicate)
78-
const o = this.termMapping(value, this.subject.dataset, this.subject.factory)?.term as Quad_Object // TODO: guards
78+
const o = this.termMapping(value, this.subject.dataset, this.subject.factory) as Quad_Object // TODO: guards
7979
const q = this.subject.factory.quad(s, p, o)
8080
return q
8181
}
8282

8383
private get matches(): DatasetCore {
8484
const p = this.subject.factory.namedNode(this.predicate)
85-
return this.subject.dataset.match(this.subject.term, p)
85+
return this.subject.dataset.match(this.subject as Term, p)
8686
}
8787
}

src/mapping/ObjectMapping.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { ITermWrapperConstructor } from "../type/ITermWrapperConstructor.js
33
import type { TermWrapper } from "../TermWrapper.js"
44
import type { ITermMapping } from "../type/ITermMapping.js"
55
import { RdfList } from "../RdfList.js"
6+
import type { Term } from "@rdfjs/types"
67

78

89
/*
@@ -18,10 +19,10 @@ import { RdfList } from "../RdfList.js"
1819
*/
1920
export namespace ObjectMapping {
2021
export function as<T>(constructor: ITermWrapperConstructor<T>): IValueMapping<T> {
21-
return (termWrapper: TermWrapper) => new constructor(termWrapper.term, termWrapper.dataset, termWrapper.factory)
22+
return (termWrapper: TermWrapper) => new constructor(termWrapper as Term, termWrapper.dataset, termWrapper.factory)
2223
}
2324

2425
export function asList<T>(subject: TermWrapper, predicate: string, valueMapping: IValueMapping<T>, termMapping: ITermMapping<T>): IValueMapping<T[]> {
25-
return w => new RdfList(w.term, subject, predicate, valueMapping, termMapping)
26+
return w => new RdfList(w as Term, subject, predicate, valueMapping, termMapping)
2627
}
2728
}

src/mapping/ValueMapping.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,31 @@ import type { TermWrapper } from "../TermWrapper.js"
1010
export namespace ValueMapping {
1111
export function blankNodeToString(termWrapper: TermWrapper): string {
1212
// TODO: Throw typed error
13-
if (termWrapper.term.termType != "BlankNode") {
14-
throw Error(`Value mapping expected blank node but got ${termWrapper.term.termType}`)
13+
if (termWrapper.termType != "BlankNode") {
14+
throw Error(`Value mapping expected blank node but got ${termWrapper.termType}`)
1515
}
1616
return iriOrBlankNodeToString(termWrapper)
1717
}
1818

1919
export function literalToDate(termWrapper: TermWrapper): Date {
2020
// TODO: Check term type
21-
return new Date(termWrapper.term.value)
21+
return new Date(termWrapper.value)
2222
}
2323

2424
// TODO: Lang string dictionary value mapping
2525
export function literalToLangString(termWrapper: TermWrapper): ILangString {
2626
// TODO: Check term type
27-
const x = termWrapper.term as Literal
28-
return { lang: x.language, string: x.value }
27+
return { lang: termWrapper.language, string: termWrapper.value }
2928
}
3029

3130
export function literalToNumber(termWrapper: TermWrapper): number {
3231
// TODO: Check term type
33-
return Number(termWrapper.term.value)
32+
return Number(termWrapper.value)
3433
}
3534

3635
export function literalToString(termWrapper: TermWrapper): string {
3736
// TODO: Check term type
38-
return termWrapper.term.value
37+
return termWrapper.value
3938
}
4039

4140
export function iriToString(termWrapper: TermWrapper): string {
@@ -44,10 +43,10 @@ export namespace ValueMapping {
4443
}
4544

4645
export function iriOrBlankNodeToString(termWrapper: TermWrapper): string {
47-
return termWrapper.term.value
46+
return termWrapper.value
4847
}
4948

5049
export function asIs(termWrapper: TermWrapper): Term {
51-
return termWrapper.term
50+
return termWrapper as Term
5251
}
5352
}

src/something.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type { BaseQuad, DataFactory, DatasetCore, Literal, NamedNode, Term } from '@rdfjs/types'
2+
3+
type TermType = Term["termType"]
4+
5+
interface AnyTerm {
6+
readonly termType: TermType
7+
readonly value: string
8+
readonly language: string
9+
readonly direction: "ltr" | "rtl" | "" | null | undefined
10+
readonly datatype: NamedNode
11+
readonly subject: Term
12+
readonly predicate: Term
13+
readonly object: Term
14+
readonly graph: Term
15+
16+
equals(other: Term | null | undefined): boolean
17+
}
18+
19+
abstract class WrapperTerm implements AnyTerm {
20+
protected constructor(private readonly original: Term) {
21+
}
22+
23+
get termType(): TermType {
24+
return this.original.termType
25+
}
26+
27+
get value(): string {
28+
return this.original.value
29+
}
30+
31+
get language(): string {
32+
return (this.original as Literal).language
33+
}
34+
35+
get direction(): "ltr" | "rtl" | "" | null | undefined {
36+
return (this.original as Literal).direction
37+
}
38+
39+
get datatype(): NamedNode {
40+
return (this.original as Literal).datatype
41+
}
42+
43+
get subject(): Term {
44+
return (this.original as BaseQuad).subject
45+
}
46+
47+
get predicate(): Term {
48+
return (this.original as BaseQuad).predicate
49+
}
50+
51+
get object(): Term {
52+
return (this.original as BaseQuad).object
53+
}
54+
55+
get graph(): Term {
56+
return (this.original as BaseQuad).graph
57+
}
58+
59+
equals(other: Term | null | undefined): boolean {
60+
return this.original.equals(other);
61+
}
62+
}
63+
64+
export abstract class Something extends WrapperTerm {
65+
public readonly dataset: DatasetCore;
66+
public readonly factory: DataFactory;
67+
68+
public constructor(term: string, dataset: DatasetCore, factory: DataFactory);
69+
public constructor(term: Term, dataset: DatasetCore, factory: DataFactory);
70+
public constructor(term: string | Term, dataset: DatasetCore, factory: DataFactory) {
71+
super(typeof term === "string" ? factory.namedNode(term) : term)
72+
73+
this.dataset = dataset;
74+
this.factory = factory;
75+
}
76+
}

test/unit/term_wrapper.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { DataFactory } from "n3"
44
import { Child } from "./model/Child.js"
55
import { datasetFromRdf } from "./util/datasetFromRdf.js"
66
import { Parent } from "./model/Parent.js"
7+
import type { Term } from "@rdfjs/types"
78

89

910
const rdf = `
@@ -187,7 +188,7 @@ describe("Term Wrapper", async () => {
187188

188189
describe("Recursion Mapping", async () => {
189190
it("get recursive wrapped term", () => {
190-
assert.equal(parent.term.equals(parent.hasRecursive.hasRecursive.hasRecursive.term), true)
191+
assert.equal(parent.equals(parent.hasRecursive.hasRecursive.hasRecursive as Term), true)
191192
})
192193

193194
it("set recursive property", () => {
@@ -197,7 +198,7 @@ describe("Term Wrapper", async () => {
197198
// TODO: check for typed error singular no value
198199
assert.throws(() => parent.hasRecursive)
199200
parent.hasRecursive = "x"
200-
assert.equal(parent.hasRecursive.hasRecursive.hasRecursive.term.value, "x")
201+
assert.equal(parent.hasRecursive.hasRecursive.hasRecursive.value, "x")
201202
})
202203

203204
// TODO: test recursion in wrapping set

0 commit comments

Comments
 (0)