Skip to content

Commit

Permalink
feat: replace manages with memberAssertion
Browse files Browse the repository at this point in the history
  • Loading branch information
tpluscode committed Jul 8, 2021
1 parent 52beb52 commit 9894812
Show file tree
Hide file tree
Showing 14 changed files with 119 additions and 65 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-peas-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"alcaeus": minor
---

Added support for `hydra:memberAssertion`
4 changes: 2 additions & 2 deletions docs/latest/representations/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
Hydra specifications defines an interface for collections. A basic collection is represented by an array of its items (`member`) and the total number of items.

```typescript
import { ManagesBlock, Resource, View } from '@rdfine/hydra'
import { MemberAssertion, Resource, View } from '@rdfine/hydra'

interface Collection {
readonly totalItems: number;
readonly member: Resource[];
readonly views?: View[];
readonly manages: ManagesBlock[];
readonly manages: MemberAssertion[];
}
```

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@
"@rdf-esm/sink-map": "^0.5.0",
"@rdf-esm/term-map": "^0.5.0",
"@rdf-esm/term-set": "^0.5.0",
"@rdfine/hydra": "^0.6.6",
"@rdfine/hydra": "^0.7.1",
"@rdfine/rdf": "^0.5.4",
"@rdfjs/formats-common": "^2.1.0",
"@rdfjs/types": "*",
"@tpluscode/rdf-ns-builders": "^1.0.0",
"@tpluscode/rdfine": "^0.5.27",
"@tpluscode/rdfine": "^0.5.29",
"clownface": "^1",
"isomorphic-fetch": "^3.0.0",
"isomorphic-form-data": "^2.0.0",
Expand Down
15 changes: 10 additions & 5 deletions src/Resources/CoreMixins/HydraResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { DatasetCore, Term } from 'rdf-js'
import TermMap from '@rdf-esm/term-map'
import { GraphPointer } from 'clownface'
import type { HydraClient } from '../../alcaeus'
import type { ManagesBlockPattern } from '../Mixins/ManagesBlock'
import type { MemberAssertionPattern } from '../Mixins/MemberAssertion'
import { RuntimeOperation, createMixin } from '../Operation'

declare module '@tpluscode/rdfine' {
Expand All @@ -30,7 +30,7 @@ declare module '@tpluscode/rdfine' {
/**
* Gets objects of hydra:collection property
*/
getCollections(filter?: ManagesBlockPattern): RdfResource<D>[]
getCollections(filter?: MemberAssertionPattern): RdfResource<D>[]
}
}

Expand Down Expand Up @@ -111,10 +111,15 @@ export function createHydraResourceMixin(alcaeus: () => HydraClient<any>) {
return [...map.values()]
}

public getCollections(filter?: ManagesBlockPattern) {
public getCollections(filter?: MemberAssertionPattern) {
if (filter) {
return this.collection.filter((c) => c.manages &&
c.manages.find((managesBlock) => managesBlock.matches(filter)))
return this.collection.filter((c) => {
const memberAssertions = [
...c.memberAssertion || [],
...c.manages || [],
]
return memberAssertions.find((managesBlock) => managesBlock.matches(filter))
})
}

return this.collection
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
import type { Constructor, RdfResource, ResourceIdentifier } from '@tpluscode/rdfine'
import type { ExtendingConstructor, RdfResource, ResourceIdentifier } from '@tpluscode/rdfine'
import { namespace } from '@tpluscode/rdfine'
import type { Class, ManagesBlock } from '@rdfine/hydra'
import type { Class, MemberAssertion } from '@rdfine/hydra'
import type { Property } from '@rdfine/rdf'
import type { MultiPointer } from 'clownface'
import type { NamedNode } from 'rdf-js'
import { hydra, rdf } from '@tpluscode/rdf-ns-builders'

export interface ManagesBlockPattern {
export interface MemberAssertionPattern {
subject?: string | RdfResource | NamedNode
predicate?: string | Property | NamedNode
object?: string | Class | NamedNode
}

interface MemberAssertionEx {
/**
* Checks if the current manages block matches the given pattern
* @param filter {MemberAssertionPattern}
*/
matches(filter: MemberAssertionPattern): boolean
}

declare module '@rdfine/hydra' {
export interface ManagesBlock {
/**
* Checks if the current manages block matches the given pattern
* @param filter {ManagesBlockPattern}
*/
matches(filter: ManagesBlockPattern): boolean
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface MemberAssertion extends MemberAssertionEx {
}
}

Expand All @@ -34,10 +38,10 @@ function getUri(factory: MultiPointer, resource: string | RdfResource | NamedNod
return resource
}

export function ManagesBlockMixin<TBase extends Constructor<Omit<ManagesBlock, 'matches'>>>(Base: TBase) {
export function MemberAssertionMixin<TBase extends ExtendingConstructor<MemberAssertion, MemberAssertionEx>>(Base: TBase) {
@namespace(hydra)
class ManagesBlockClass extends Base implements ManagesBlock {
public matches({ subject = '', predicate = rdf.type, object = '' }: ManagesBlockPattern): boolean {
class MemberAssertionClass extends Base implements MemberAssertionEx {
public matches({ subject = '', predicate = rdf.type, object = '' }: MemberAssertionPattern): boolean {
const predicateId = getUri(this.pointer, predicate)
const objectId = getUri(this.pointer, object)
const subjectId = getUri(this.pointer, subject)
Expand All @@ -56,9 +60,9 @@ export function ManagesBlockMixin<TBase extends Constructor<Omit<ManagesBlock, '
}
}

return ManagesBlockClass
return MemberAssertionClass
}

ManagesBlockMixin.shouldApply = (res: RdfResource) => {
return res.pointer.in(hydra.manages).terms.length > 0
MemberAssertionMixin.shouldApply = (res: RdfResource) => {
return res.pointer.in([hydra.manages, hydra.memberAssertion]).terms.length > 0
}
5 changes: 2 additions & 3 deletions src/Resources/Mixins/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import './Class'
import './Operation'
import './SupportedProperty'
import './PartialCollectionView'
import './ApiDocumentation'
import './DocumentedResource'
import './ManagesBlock'
import './MemberAssertion'
import './RdfProperty'

export { ApiDocumentationMixin } from './ApiDocumentation'
export { ClassMixin } from './Class'
export { DocumentedResourceMixin } from './DocumentedResource'
export { ManagesBlockMixin } from './ManagesBlock'
export { MemberAssertionMixin } from './MemberAssertion'
export { PartialCollectionViewMixin } from './PartialCollectionView'
export { RdfPropertyMixin } from './RdfProperty'
export { OperationMixin } from './Operation'
Expand Down
2 changes: 1 addition & 1 deletion src/inferences/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { inferTypesFromPropertyRanges } from './propertyTypes'
export { addExplicitStatementsInferredFromManagesBlock } from './managesBlock'
export { addExplicitStatementsInferredFromMemberAssertion } from './memberAssertion'
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import * as RDF from '@rdf-esm/data-model'
import { BaseQuad, DatasetCore } from 'rdf-js'
import { hydra } from '@tpluscode/rdf-ns-builders'

export function * addExplicitStatementsInferredFromManagesBlock(dataset: DatasetCore): Iterable<BaseQuad> {
for (const collection of cf({ dataset }).has(hydra.manages).toArray()) {
const managesBlocks = collection.out(hydra.manages).toArray()
export function * addExplicitStatementsInferredFromMemberAssertion(dataset: DatasetCore): Iterable<BaseQuad> {
for (const collection of cf({ dataset }).has([hydra.manages, hydra.memberAssertion]).toArray()) {
const managesBlocks = collection.out([hydra.manages, hydra.memberAssertion]).toArray()

for (const member of collection.out(hydra.member).toArray()) {
for (const managesBlock of managesBlocks) {
Expand Down
32 changes: 31 additions & 1 deletion tests/Resources/HydraResource-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,37 @@ describe('HydraResource', () => {
<http://example.com/collection3> ,
<http://example.com/collection4> .
<http://example.com/collection1> ${hydra.manages} [
<http://example.com/collection1> a ${hydra.Collection} ; ${hydra.manages} [
${hydra.object} <http://example.org/Class> ;
${hydra.property} ${rdf.type}
] .
`)
const resource = new HydraResource(cf({
dataset: await $rdf.dataset().import(resourceGraph),
term: namedNode('http://example.com/'),
}))

// when
const collections = resource.getCollections({
object: 'http://example.org/Class',
})

// then
expect(collections.length).toBe(1)
expect(collections[0].id.value).toBe('http://example.com/collection1')
})

it('returns collections matching member assertion Class given by id', async () => {
// given
const resourceGraph = parse(
turtle`
<http://example.com/> ${hydra.collection}
<http://example.com/collection1> ,
<http://example.com/collection2> ,
<http://example.com/collection3> ,
<http://example.com/collection4> .
<http://example.com/collection1> a ${hydra.Collection} ; ${hydra.memberAssertion} [
${hydra.object} <http://example.org/Class> ;
${hydra.property} ${rdf.type}
] .
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ import * as Hydra from '@rdfine/hydra'
import cf, { GraphPointer } from 'clownface'
import $rdf from 'rdf-ext'
import { BlankNode, DatasetCore } from 'rdf-js'
import { ManagesBlockMixin } from '../../../src/Resources/Mixins/ManagesBlock'
import { MemberAssertionMixin } from '../../../src/Resources/Mixins/MemberAssertion'
import { foaf, hydra, rdf } from '@tpluscode/rdf-ns-builders'

class ManagesBlock extends ManagesBlockMixin(Hydra.ManagesBlockMixin(Resource)) {}
class MemberAssertion extends MemberAssertionMixin(Hydra.MemberAssertionMixin(Resource)) {}

describe('ManagesBlock', () => {
describe('MemberAssertion', () => {
let dataset: DatasetCore
let node: GraphPointer<BlankNode>
let managesBlock: ManagesBlock
let managesBlock: MemberAssertion

beforeEach(() => {
dataset = $rdf.dataset()
node = cf({ dataset }).blankNode()

managesBlock = new ManagesBlock(node)
managesBlock = new MemberAssertion(node)
})

describe('shouldApply', () => {
Expand All @@ -27,7 +27,18 @@ describe('ManagesBlock', () => {
node.addIn(hydra.manages, node.blankNode())

// when
const result = ManagesBlockMixin.shouldApply(managesBlock)
const result = MemberAssertionMixin.shouldApply(managesBlock)

// then
expect(result).toBeTruthy()
})

it('should return true if resource is object of hydra:memberAssertion property', () => {
// given
node.addIn(hydra.memberAssertion, node.blankNode())

// when
const result = MemberAssertionMixin.shouldApply(managesBlock)

// then
expect(result).toBeTruthy()
Expand Down
4 changes: 2 additions & 2 deletions tests/Resources/_TestResource.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import RdfResource from '@tpluscode/rdfine'
import * as Hydra from '@rdfine/hydra'
import { Criteria, RecursiveStopConditions } from '../../src/Resources/CoreMixins/OperationFinder'
import { ManagesBlockPattern } from '../../src/Resources/Mixins/ManagesBlock'
import { MemberAssertionPattern } from '../../src/Resources/Mixins/MemberAssertion'
import { RuntimeOperation } from '../../src/Resources/Operation'

export class Resource extends RdfResource implements Hydra.Resource {
Expand All @@ -17,7 +17,7 @@ export class Resource extends RdfResource implements Hydra.Resource {
return []
}

public getCollections(filter?: ManagesBlockPattern): Resource[] {
public getCollections(filter?: MemberAssertionPattern): Resource[] {
return []
}

Expand Down
8 changes: 4 additions & 4 deletions tests/inferences/managesBlock-spec-graphs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const managesWithTypeGraph = `
hydra:member <member1>, <member2> .
`

const multipleManagesBlocksGraph = `
const multipleMemberAssertionsGraph = `
<collection>
a hydra:Collection ;
hydra:manages [
Expand All @@ -23,7 +23,7 @@ const multipleManagesBlocksGraph = `
hydra:member <member1>, <member2> .
`

const incompleteManagesBlocksGraph = `
const incompleteMemberAssertionsGraph = `
<collection>
a hydra:Collection ;
hydra:manages [
Expand All @@ -36,5 +36,5 @@ const incompleteManagesBlocksGraph = `
hydra:member <member1>, <member2> .`

export const managesWithType = createGraph(managesWithTypeGraph)
export const multipleManagesBlocks = createGraph(multipleManagesBlocksGraph)
export const incompleteManagesBlocks = createGraph(incompleteManagesBlocksGraph)
export const multipleMemberAssertions = createGraph(multipleMemberAssertionsGraph)
export const incompleteMemberAssertions = createGraph(incompleteMemberAssertionsGraph)
12 changes: 6 additions & 6 deletions tests/inferences/managesBlock-spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addExplicitStatementsInferredFromManagesBlock } from '../../src/inferences'
import { addExplicitStatementsInferredFromMemberAssertion } from '../../src/inferences'
import * as specGraphs from './managesBlock-spec-graphs'

describe('manages block inference', () => {
Expand All @@ -7,29 +7,29 @@ describe('manages block inference', () => {
const dataset = await specGraphs.managesWithType()

// when
dataset.addAll([...addExplicitStatementsInferredFromManagesBlock(dataset)])
dataset.addAll([...addExplicitStatementsInferredFromMemberAssertion(dataset)])

// then
expect(dataset.toCanonical()).toMatchSnapshot()
})

it('adds triples for multiple manages blocks', async () => {
// given
const dataset = await specGraphs.multipleManagesBlocks()
const dataset = await specGraphs.multipleMemberAssertions()

// when
dataset.addAll([...addExplicitStatementsInferredFromManagesBlock(dataset)])
dataset.addAll([...addExplicitStatementsInferredFromMemberAssertion(dataset)])

// then
expect(dataset.toCanonical()).toMatchSnapshot()
})

it('ignores malformed manages blocks', async () => {
// given
const dataset = await specGraphs.incompleteManagesBlocks()
const dataset = await specGraphs.incompleteMemberAssertions()

// when
dataset.addAll([...addExplicitStatementsInferredFromManagesBlock(dataset)])
dataset.addAll([...addExplicitStatementsInferredFromMemberAssertion(dataset)])

// then
expect(dataset.toCanonical()).toMatchSnapshot()
Expand Down
Loading

0 comments on commit 9894812

Please sign in to comment.