diff --git a/package-lock.json b/package-lock.json index 12cb986..5e3fd75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rdf-lens", - "version": "1.3.1", + "version": "1.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rdf-lens", - "version": "1.3.1", + "version": "1.3.3", "license": "MIT", "dependencies": { "@rdfjs/types": "^1.1.0", diff --git a/package.json b/package.json index 9ed9dc2..6373e68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rdf-lens", - "version": "1.3.3", + "version": "1.3.4", "main": "./dist/index.js", "type": "module", "exports": { diff --git a/src/shacl.ts b/src/shacl.ts index 02490c8..8644c59 100644 --- a/src/shacl.ts +++ b/src/shacl.ts @@ -67,7 +67,7 @@ export function toLens( return field.path .thenFlat(thenListExtract.or(noListExtract).asMulti()) .thenAll(field.extract) - .map((x) => x.filter((x) => !!x)) + .map((x) => x.filter((x) => x !== undefined)) .map((xs) => { if (xs.length < minCount) { throw `${shape.ty}:${field.name} required at least ${minCount} elements, found ${xs.length}`; @@ -78,7 +78,7 @@ export function toLens( return xs; }) .map((x) => { - const out = x.filter((x) => !!x); + const out = x.filter((x) => x !== undefined); if (maxCount < 2) { return out[0]; } else { diff --git a/test/regressions/maregraph/data.ttl b/test/regressions/maregraph/data.ttl new file mode 100644 index 0000000..0a4e909 --- /dev/null +++ b/test/regressions/maregraph/data.ttl @@ -0,0 +1,25 @@ +_:df_9_1 . +_:df_9_1 . +_:df_9_1 <> . + . + "2004-03-01T23:00:00Z"^^ . + . + . + . + "2004-03-01T23:00:00Z"^^ . + . + ": Named after Skikda city"@en . + ": Removed from GEBCO gazetteer 2010"@en . + "Coordinates in ACUF: Latitude: 37.133333; Longitude: 6.783333"@en . + "Skikda Canyons"@en . + " POINT (6.78333333 37.13333333)"^^ . + . + _:b5_n3-69958 . + . +_:b5_n3-69958 . +_:b5_n3-69958 . +_:b5_n3-69958 "45863" . +<> . +<> "false" . +<> "true" . +<> . diff --git a/test/regressions/maregraph/maregraph.test.ts b/test/regressions/maregraph/maregraph.test.ts new file mode 100644 index 0000000..825a045 --- /dev/null +++ b/test/regressions/maregraph/maregraph.test.ts @@ -0,0 +1,92 @@ +import { describe, expect, test } from "vitest"; +import { readFile } from "fs/promises"; +import type * as RDF from "@rdfjs/types"; +import { RDF as RDFT, RelationType, SDS } from "@treecg/types"; +import { Parser } from "n3"; + +import { extractShapes, match, subject } from "../../../src/index"; + +export type Record = { + stream: string; + payload: string; + buckets: string[]; + dataless?: boolean; +}; + +export type Bucket = { + id: string; + streamId: string; + immutable?: boolean; + root?: boolean; + empty?: boolean; +}; + +export type RdfThing = { + id: RDF.Term; + quads: RDF.Quad[]; +}; + +export type Relation = { + type: RelationType; + stream: string; + origin: string; + bucket: string; + value?: RdfThing; + path?: RdfThing; +}; + +async function setupLenses() { + const shape_str = await readFile(__dirname + "/shape.ttl", { + encoding: "utf8", + }); + const Shapes = extractShapes(new Parser().parse(shape_str)); + console.log(Shapes); + const RecordLens = match(undefined, SDS.terms.payload, undefined) + .thenAll(subject) + .thenSome(Shapes.lenses["Record"]); + + const BucketLens = match( + undefined, + RDFT.terms.type, + SDS.terms.custom("Bucket"), + ) + .thenAll(subject) + .thenSome(Shapes.lenses["Bucket"]); + + const RelationLens = match( + undefined, + RDFT.terms.type, + SDS.terms.custom("Relation"), + ) + .thenAll(subject) + .thenSome(Shapes.lenses["Relation"]); + + return { RecordLens, BucketLens, RelationLens }; +} + +async function getData() { + const data_str = await readFile(__dirname + "/data.ttl", { + encoding: "utf8", + }); + const quads = new Parser().parse(data_str); + + return quads.filter((q) => + q.graph.equals(SDS.terms.custom("DataDescription")), + ); +} + +describe("test empty ids get extracted", async () => { + const lenses = await setupLenses(); + const data = await getData(); + + test("Records get extracted", () => { + const records = lenses.RecordLens.execute(data); + + expect(records.length).toBe(1); + expect(records[0].buckets.length).toBe(1); + }); + test("Records get extracted", () => { + const buckets = lenses.BucketLens.execute(data); + expect(buckets.length).toBe(1); + }); +}); diff --git a/test/regressions/maregraph/shape.ttl b/test/regressions/maregraph/shape.ttl new file mode 100644 index 0000000..a199eae --- /dev/null +++ b/test/regressions/maregraph/shape.ttl @@ -0,0 +1,119 @@ +@prefix cidoc: . +@prefix rdfl: . +@prefix sosa: . +@prefix dcterms: . +@prefix xsd: . +@prefix sh: . +@prefix sds: . + +[ ] a sh:NodeShape; + sh:targetClass ; + sh:property [ + sh:name "stream"; + sh:path sds:stream; + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "payload"; + sh:path sds:payload; + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "buckets"; + sh:path sds:bucket; + sh:datatype xsd:string; + ], [ + sh:name "dataless"; + sh:path sds:dataless; + sh:datatype xsd:boolean; + sh:minCount 0; + sh:maxCount 1; + ]. + +[ ] a sh:NodeShape; + sh:targetClass ; + sh:property [ + sh:name "id"; + sh:path ( ); + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "streamId"; + sh:path sds:stream; + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "immutable"; + sh:path sds:immutable; + sh:datatype xsd:boolean; + sh:maxCount 1; + ], [ + sh:name "root"; + sh:path sds:isRoot; + sh:datatype xsd:boolean; + sh:maxCount 1; + ], [ + sh:name "empty"; + sh:path sds:empty; + sh:datatype xsd:boolean; + sh:maxCount 1; + ]. + +[ ] a sh:NodeShape; + sh:targetClass ; + sh:property [ + sh:name "type"; + sh:path sds:relationType; + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "stream"; + sh:path ( [ sh:inversePath sds:relation ] sds:stream ); + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "origin"; + sh:path [ sh:inversePath sds:relation ]; + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "bucket"; + sh:path sds:relationBucket; + sh:datatype xsd:string; + sh:minCount 1; + sh:maxCount 1; + ], [ + sh:name "path"; + sh:path sds:relationPath; + sh:class ; + sh:maxCount 1; + ], [ + sh:name "value"; + sh:path sds:relationValue; + sh:class ; + sh:maxCount 1; + ]. + +[ ] a sh:NodeShape; + sh:targetClass ; + sh:property [ + sh:name "id"; + sh:path ( ); + sh:maxCount 1; + sh:minCount 1; + sh:datatype xsd:any; + ], [ + sh:name "quads"; + sh:path ( ); + sh:maxCount 1; + sh:minCount 1; + sh:class rdfl:CBD; + ]. + diff --git a/test/regressions/maregraph/test.ts b/test/regressions/maregraph/test.ts new file mode 100644 index 0000000..bb0cfb6 --- /dev/null +++ b/test/regressions/maregraph/test.ts @@ -0,0 +1,82 @@ +import { readFile } from "fs/promises"; +import type * as RDF from "@rdfjs/types"; +import { RDF as RDFT, RelationType, SDS } from "@treecg/types"; +import { Parser } from "n3"; + +import { extractShapes, match, subject } from "../../../src/index"; + +export type Record = { + stream: string; + payload: string; + buckets: string[]; + dataless?: boolean; +}; + +export type Bucket = { + id: string; + streamId: string; + immutable?: boolean; + root?: boolean; + empty?: boolean; +}; + +export type RdfThing = { + id: RDF.Term; + quads: RDF.Quad[]; +}; + +export type Relation = { + type: RelationType; + stream: string; + origin: string; + bucket: string; + value?: RdfThing; + path?: RdfThing; +}; + +async function setupLenses() { + const shape_str = await readFile("/shape.ttl", { encoding: "utf8" }); + const Shapes = extractShapes(new Parser().parse(shape_str)); + const RecordLens = match(undefined, SDS.terms.payload, undefined) + .thenAll(subject) + .thenSome(Shapes.lenses["Record"]); + + const BucketLens = match( + undefined, + RDFT.terms.type, + SDS.terms.custom("Bucket"), + ) + .thenAll(subject) + .thenSome(Shapes.lenses["Bucket"]); + + const RelationLens = match( + undefined, + RDFT.terms.type, + SDS.terms.custom("Relation"), + ) + .thenAll(subject) + .thenSome(Shapes.lenses["Relation"]); + + return { RecordLens, BucketLens, RelationLens }; +} + +async function getData() { + const data_str = await readFile("/data.ttl", { encoding: "utf8" }); + const quads = new Parser().parse(data_str); + + return quads.filter((q) => + q.graph.equals(SDS.terms.custom("DataDescription")), + ); +} + +describe("test empty ids get extracted", async () => { + const lenses = await setupLenses(); + const data = await getData(); + + test("Records get extracted", () => { + const records = lenses.RecordLens.execute(data); + console.log(records); + expect(2).toBe(4); + }); + const buckets = lenses.BucketLens.execute(data); +});