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

outE (out edges) and inE (in edges) methods #62

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
44 changes: 44 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ A graph pointer object, which points at 0..N nodes within a dataset
* [.literal(values, [languageOrDatatype])](#Clownface+literal) ⇒ [<code>Clownface</code>](#Clownface)
* [.namedNode(values)](#Clownface+namedNode) ⇒ [<code>Clownface</code>](#Clownface)
* [.in([predicates])](#Clownface+in) ⇒ [<code>Clownface</code>](#Clownface)
* [.inE([predicates])](#Clownface+inE) ⇒ [<code>Clownface</code>](#Clownface)
* [.out([predicates], [options])](#Clownface+out) ⇒ [<code>Clownface</code>](#Clownface)
* [.outE([predicates], [options])](#Clownface+outE) ⇒ [<code>Clownface</code>](#Clownface)
* [.has(predicates, [objects])](#Clownface+has) ⇒ [<code>Clownface</code>](#Clownface)
* [.addIn(predicates, subjects, [callback])](#Clownface+addIn) ⇒ [<code>Clownface</code>](#Clownface)
* [.addOut(predicates, objects, [callback])](#Clownface+addOut) ⇒ [<code>Clownface</code>](#Clownface)
Expand Down Expand Up @@ -292,6 +294,25 @@ Creates a graph pointer to nodes which are linked to the current pointer by `pre
</tr> </tbody>
</table>

<a name="Clownface+inE"></a>

### clownface.inE([predicates]) ⇒ [<code>Clownface</code>](#Clownface)
A similar operation to in, but instead of returning the objects, it returns pointers to the matching predicates

**Kind**: instance method of [<code>Clownface</code>](#Clownface)
<table>
<thead>
<tr>
<th>Param</th><th>Type</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>[predicates]</td><td><code>Term</code> | <code>Array.&lt;Term&gt;</code> | <code><a href="#Clownface">Clownface</a></code> | <code><a href="#Clownface">Array.&lt;Clownface&gt;</a></code></td><td><p>one or more RDF/JS term identifying a property</p>
</td>
</tr> </tbody>
</table>

<a name="Clownface+out"></a>

### clownface.out([predicates], [options]) ⇒ [<code>Clownface</code>](#Clownface)
Expand All @@ -316,6 +337,29 @@ following any predicates in an array, starting from the subject(s) (current grap
</tr> </tbody>
</table>

<a name="Clownface+outE"></a>

### clownface.outE([predicates], [options]) ⇒ [<code>Clownface</code>](#Clownface)
A similar operation to out, but instead of returning the objects, it returns pointers to the matching predicates

**Kind**: instance method of [<code>Clownface</code>](#Clownface)
<table>
<thead>
<tr>
<th>Param</th><th>Type</th><th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>[predicates]</td><td><code>Term</code> | <code>Array.&lt;Term&gt;</code> | <code><a href="#Clownface">Clownface</a></code> | <code><a href="#Clownface">Array.&lt;Clownface&gt;</a></code></td><td><p>any predicates to follow</p>
</td>
</tr><tr>
<td>[options]</td><td><code>object</code></td><td></td>
</tr><tr>
<td>[options.language]</td><td><code>string</code> | <code>Array.&lt;string&gt;</code> | <code>undefined</code></td><td></td>
</tr> </tbody>
</table>

<a name="Clownface+has"></a>

### clownface.has(predicates, [objects]) ⇒ [<code>Clownface</code>](#Clownface)
Expand Down
28 changes: 28 additions & 0 deletions lib/Clownface.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,19 @@ class Clownface {
return Clownface.fromContext(context)
}

/**
* A similar operation to {@link in}, but instead of returning the objects, it returns pointers to the matching predicates
* @param {Term|Term[]|Clownface|Clownface[]} [predicates] one or more RDF/JS term identifying a property
* @returns {Clownface}
*/
inProp (predicates) {
predicates = this._toTermArray(predicates)

const context = this._context.reduce((all, current) => all.concat(current.inProp(predicates)), [])

return Clownface.fromContext(context)
}

/**
* Creates a graph pointer to the result nodes after following a predicate, or after
* following any predicates in an array, starting from the subject(s) (current graph pointer) to the objects.
Expand All @@ -311,6 +324,21 @@ class Clownface {
return Clownface.fromContext(context)
}

/**
* A similar operation to {@link out}, but instead of returning the objects, it returns pointers to the matching predicates
* @param {Term|Term[]|Clownface|Clownface[]} [predicates] any predicates to follow
* @param {object} [options]
* @param {string | string[] | undefined} [options.language]
* @returns {Clownface}
*/
outProp (predicates, options = {}) {
predicates = this._toTermArray(predicates)

const context = this._context.reduce((all, current) => all.concat(current.outProp(predicates, options)), [])

return Clownface.fromContext(context)
}

/**
* Creates a graph pointer to nodes which are subjects of predicates, optionally also with specific objects
*
Expand Down
14 changes: 14 additions & 0 deletions lib/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ class Context {
})
}

inProp (predicate) {
return this.matchProperty(null, predicate, toArray(this.term), toArray(this.graph), 'predicate').map(subject => {
return this.clone({ value: subject })
})
}

out (predicate, { language } = {}) {
let objects = this.matchProperty(toArray(this.term), predicate, null, toArray(this.graph), 'object')

Expand All @@ -42,6 +48,14 @@ class Context {
})
}

outProp (predicate) {
let predicates = this.matchProperty(toArray(this.term), predicate, null, toArray(this.graph), 'predicate')

return predicates.map(predicate => {
return this.clone({ value: predicate })
})
}

addIn (predicates, subjects) {
const context = []

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clownface",
"version": "1.4.0",
"version": "1.4.1",
cristianvasquez marked this conversation as resolved.
Show resolved Hide resolved
"description": "Simple but powerful graph traversing library",
"main": "index.js",
"scripts": {
Expand Down
80 changes: 80 additions & 0 deletions test/Clownface/inProp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* global describe, it */

const assert = require('assert')
const clownface = require('../..')
const loadExample = require('../support/example')
const rdf = require('../support/factory')
const ns = require('../support/namespace')
const Clownface = require('../../lib/Clownface')

describe('.inProp', () => {
it('should be a function', () => {
const cf = clownface({ dataset: rdf.dataset() })

assert.strictEqual(typeof cf.inProp, 'function')
})

it('should return a new Clownface instance', async () => {
const cf = clownface({
dataset: await loadExample(),
value: '2311 North Los Robles Avenue, Aparment 4A'
})

const result = cf.inProp(rdf.namedNode('http://schema.org/streetAddress'))

assert(result instanceof Clownface)
assert.notStrictEqual(result, cf)
})

it('should search object -> subject without predicate', async () => {
const cf = clownface({
dataset: await loadExample(),
term: ns.tbbtp('bernadette-rostenkowski')
})

const result = cf.inProp()

assert.strictEqual(result._context.length, 8)
})

it('should search object -> subject with predicate', async () => {
const cf = clownface({
dataset: await loadExample(),
value: '2311 North Los Robles Avenue, Aparment 4A'
})

const result = cf.inProp(rdf.namedNode('http://schema.org/streetAddress'))

assert.strictEqual(result._context.length, 2)
assert.strictEqual(result._context[0].term.termType, 'NamedNode')
assert.strictEqual(result._context[0].term.value, 'http://schema.org/streetAddress')
})

it('should support multiple predicate values in an array', async () => {
const cf = clownface({
dataset: await loadExample(),
term: rdf.namedNode('http://localhost:8080/data/person/bernadette-rostenkowski')
})

const result = cf.inProp([
rdf.namedNode('http://schema.org/spouse'),
rdf.namedNode('http://schema.org/knows')
])

assert.strictEqual(result._context.length, 8)
})

it('should support clownface objects as predicates', async () => {
const cf = clownface({
dataset: await loadExample(),
term: rdf.namedNode('http://localhost:8080/data/person/bernadette-rostenkowski')
})

const result = cf.inProp(cf.node([
rdf.namedNode('http://schema.org/spouse'),
rdf.namedNode('http://schema.org/knows')
]))

assert.strictEqual(result._context.length, 8)
})
})
79 changes: 79 additions & 0 deletions test/Clownface/outProp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const { describe, it } = require('mocha')
const assert = require('assert')
const clownface = require('../..')
const loadExample = require('../support/example')
const rdf = require('../support/factory')
const Clownface = require('../../lib/Clownface')
const ns = require('../support/namespace')

describe('.outProp', () => {
it('should be a function', () => {
const cf = clownface({ dataset: rdf.dataset() })

assert.strictEqual(typeof cf.outProp, 'function')
})

it('should return a new Clownface instance', async () => {
const cf = clownface({
dataset: await loadExample(),
term: rdf.namedNode('http://localhost:8080/data/person/amy-farrah-fowler')
})

const result = cf.outProp(rdf.namedNode('http://schema.org/jobTitle'))

assert(result instanceof Clownface)
assert.notStrictEqual(result, cf)
})

it('should search subject -> object without predicate', async () => {
const cf = clownface({
dataset: await loadExample(),
term: ns.tbbtp('amy-farrah-fowler')
})

const result = cf.outProp()

assert.strictEqual(result._context.length, 12)
})

it('should search subject -> predicate with predicate', async () => {
const cf = clownface({
dataset: await loadExample(),
term: rdf.namedNode('http://localhost:8080/data/person/amy-farrah-fowler')
})

const result = cf.outProp(rdf.namedNode('http://schema.org/jobTitle'))

assert.strictEqual(result._context.length, 1)
assert.strictEqual(result._context[0].term.termType, 'NamedNode')
assert.strictEqual(result._context[0].term.value, 'http://schema.org/jobTitle')
})

it('should support multiple predicate values in an array', async () => {
const cf = clownface({
dataset: await loadExample(),
term: rdf.namedNode('http://localhost:8080/data/person/bernadette-rostenkowski')
})

const result = cf.outProp([
rdf.namedNode('http://schema.org/familyName'),
rdf.namedNode('http://schema.org/givenName')
])

assert.strictEqual(result._context.length, 2)
})

it('should support clownface objects as predicates', async () => {
const cf = clownface({
dataset: await loadExample(),
term: rdf.namedNode('http://localhost:8080/data/person/bernadette-rostenkowski')
})

const result = cf.outProp(cf.node([
rdf.namedNode('http://schema.org/familyName'),
rdf.namedNode('http://schema.org/givenName')
]))

assert.strictEqual(result._context.length, 2)
})
})