Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

0.3 massive commit

git-svn-id: http://scardf.googlecode.com/svn/trunk@112 9ecf9b1c-0d83-11de-8db4-35e3754be71a
  • Loading branch information...
commit 55877fe1b58920e299b52e7c99d2cc661efb1f8b 1 parent 9e32549
hrvojesimic@gmail.com authored
Showing with 318 additions and 77 deletions.
  1. +23 −10 pom.xml
  2. +11 −9 src/main/scala/net/croz/scardf/Model.scala
  3. +1 −0  src/main/scala/net/croz/scardf/QVar.scala
  4. +3 −1 src/main/scala/net/croz/scardf/Res.scala
  5. +6 −5 src/main/scala/net/croz/scardf/Vocabulary.scala
  6. +17 −2 src/main/scala/net/croz/scardf/query/SparqlQ.scala
  7. +1 −1  src/main/scala/org/scardf/augmentation.scala
  8. +5 −1 src/main/scala/org/scardf/build.scala
  9. +9 −1 src/main/scala/org/scardf/converters.scala
  10. +42 −1 src/main/scala/org/scardf/core.scala
  11. +84 −15 src/main/scala/org/scardf/graph.scala
  12. +22 −9 src/main/scala/org/scardf/graphnode.scala
  13. +23 −1 src/main/scala/org/scardf/jena/jena-graph.scala
  14. +6 −1 src/main/scala/org/scardf/jena/jena-query.scala
  15. +23 −3 src/main/scala/org/scardf/query.scala
  16. +4 −4 src/main/scala/org/scardf/triple.scala
  17. +1 −1  src/main/scala/org/scardf/typedpredicates.scala
  18. +2 −1  src/main/scala/org/scardf/vocabulary.scala
  19. +1 −1  src/test/scala/net/croz/scardf/QuerySpecs.scala
  20. +3 −3 src/test/scala/net/croz/scardf/ScardfSpecs.scala
  21. +5 −5 src/test/scala/net/croz/scardf/example_data.scala
  22. +4 −2 src/test/scala/org/scardf/converter.spec.scala
  23. +22 −0 src/test/scala/org/scardf/overview.spec.scala
View
33 pom.xml
@@ -4,7 +4,7 @@
<groupId>net.croz.scardf</groupId>
<artifactId>scardf</artifactId>
<name>Scardf</name>
- <version>0.2-SNAPSHOT</version>
+ <version>0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<description>Scala API for RDF</description>
<url>http://code.google.com/p/scardf/</url>
@@ -28,18 +28,23 @@
<url>http://code.google.com/p/scardf/issues/</url>
</issueManagement>
<properties>
- <scala.version>2.7.3</scala.version>
+ <scala.version>2.7.7</scala.version>
</properties>
<repositories>
<repository>
+ <id>repo1.maven.org</id>
+ <name>Maven2 Central Repository</name>
+ <url>http://repo1.maven.org/maven2</url>
+ </repository>
+ <repository>
<id>scala-tools.org</id>
<name>Scala-tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</repository>
<repository>
- <id>repo1.maven.org</id>
- <name>Maven2 Central Repository</name>
- <url>http://repo1.maven.org/maven2/</url>
+ <id>wp5.e-taxonomy.eu</id>
+ <name>wp5.e-taxonomy.eu</name>
+ <url>http://wp5.e-taxonomy.eu/cdmlib/mavenrepo/</url>
</repository>
</repositories>
<pluginRepositories>
@@ -53,12 +58,14 @@
<dependency>
<groupId>com.hp.hpl.jena</groupId>
<artifactId>jena</artifactId>
- <version>2.6.2</version>
+ <version>2.6.3</version>
+ <!-- version>2.6.2.ge</version-->
</dependency>
<dependency>
<groupId>com.hp.hpl.jena</groupId>
<artifactId>arq</artifactId>
- <version>2.8.1</version>
+ <version>2.8.4</version>
+ <!-- version>2.8.2-gaef</version-->
</dependency>
<dependency>
<groupId>joda-time</groupId>
@@ -79,15 +86,21 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>4.4</version>
+ <version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.specs</groupId>
+ <groupId>org.scala-tools.testing</groupId>
<artifactId>specs</artifactId>
- <version>1.4.3</version>
+ <version>1.6.2</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.scala-tools.testing</groupId>
+ <artifactId>scalacheck</artifactId>
+ <version>1.6</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
View
20 src/main/scala/net/croz/scardf/Model.scala
@@ -16,7 +16,7 @@ class Model( val jModel: JModel ) extends util.Logging {
val internalId = Model.rnd.nextLong
Model remember this
- var prefix = ""
+// var prefix = ""
val mapping = scala.collection.mutable.Map[RDFNode, Node]()
val stmtMapping = scala.collection.mutable.Map[Statement, Stmt]()
@@ -28,7 +28,7 @@ class Model( val jModel: JModel ) extends util.Logging {
def regNs( pvMappings: Pair[String, Vocabulary]* ): Unit =
regNs( Map( pvMappings map { p => (p._1, p._2.prefix) }: _* ) )
- def withPrefix( prefix: String ) = { this.prefix = prefix; this }
+ //def withPrefix( prefix: String ) = { this.prefix = prefix; this }
private def remember( r: Res ) = {
//log.info( hashCode + " " + r + " " + mapping )
@@ -39,17 +39,15 @@ class Model( val jModel: JModel ) extends util.Logging {
def getAnon() = remember( new Res( jModel.createResource( new AnonId() ), this ) )
def getAnon( id: String ) = remember( new Res( jModel createResource new AnonId( id ), this ) )
- def getRes( jRes: Resource ): Res = {
- //log.info( this + " " + jRes + " " + (mapping get jRes) + " " + mapping )
+ def getRes( jRes: Resource ): Res =
mapping.getOrElseUpdate( jRes, newRes( jRes ) ).asInstanceOf[Res]
- }
- def getRes( uri: String ): Res = getRes( jModel.getResource( this.prefix + uri ) )
+ def getRes( uri: String ): Res = getRes( jModel.getResource( uri ) )
- def /( res: Res ) = getRes( res.jResource )
+ def /( res: Res ) = getRes( res.uri )
private def newRes( jResource: Resource ) = {
- if ( jResource.canAs( classOf[RDFList] ) )
+ if ( jResource.canAs( classOf[RDFList] ) )
new RdfList( jResource.as( classOf[RDFList] ).asInstanceOf[RDFList], this )
else if ( jResource.canAs( classOf[Property] ) )
new Prop( jResource.as( classOf[Property] ).asInstanceOf[Property], this )
@@ -61,7 +59,7 @@ class Model( val jModel: JModel ) extends util.Logging {
def getProp( jProp: Property ): Prop =
mapping.getOrElseUpdate( jProp, new Prop( jProp, this ) ).asInstanceOf[Prop]
- def getProp( uri: String ): Prop = getProp( jModel.getProperty( this.prefix + uri ) )
+ def getProp( uri: String ): Prop = getProp( jModel.getProperty( uri ) )
def getRdfList( jRdfList: RDFList ): RdfList = {
//log.info( this, "get list", jRdfList, mapping.get(jRdfList), mapping )
@@ -79,6 +77,10 @@ class Model( val jModel: JModel ) extends util.Logging {
def addAll( stmts: List[Stmt] ) = stmts map add
+ def remove( stmt: Stmt ) = jModel remove stmt.jStatement
+
+ def removeAll( stmts: List[Stmt] ) = stmts map remove
+
def ++( other: Model ) = Model( jModel add other.jModel )
def listRes( assignment: Pair[Prop, Any] ) = {
View
1  src/main/scala/net/croz/scardf/QVar.scala
@@ -23,6 +23,7 @@ class QVar( val name: String ) {
case that: QVar => this.name == that.name
case _ => false
}
+
override def hashCode = name.hashCode
override val toString = "?" + name
View
4 src/main/scala/net/croz/scardf/Res.scala
@@ -176,4 +176,6 @@ class RichResIterator( jIterator: ResIterator ) extends Iterator[Res] {
override def next = Res( jIterator.next.asInstanceOf[Resource] )
}
-case class ResPropPair( s: Res, p: Prop )
+case class ResPropPair( s: Res, p: Prop ) {
+ def ->( o: Any ) = s.state( p -> o)
+}
View
11 src/main/scala/net/croz/scardf/Vocabulary.scala
@@ -7,23 +7,24 @@ import com.hp.hpl.jena.vocabulary.{RDFS => jRDFS}
import com.hp.hpl.jena.vocabulary.{XSD => jXSD}
class Vocabulary( val prefix: String ) {
- val model = new Model withPrefix prefix
+ val model = new Model //withPrefix prefix
def apply( name: String ) = pRes( name )
def \( name: String ) = pRes( name )
def ÷( name: String ) = pRes( name )
def ~( name: String ) = pProp( name )
def ^( name: String ) = pProp( name )
- def pRes( name: String ) = Res( name )( model )
- def pProp( name: String ) = Prop( name )( model )
+ def pRes( name: String ) = Res( prefix + name )( model )
+ def pProp( name: String ) = Prop( prefix + name )( model )
def wRes( r: Resource ) = Res( r, model )
def wProp( p: Property ) = Prop( p, model )
}
object RDF extends Vocabulary( jRDF.getURI ) {
val Type = wProp( jRDF.`type` )
- val first = wRes( jRDF.first )
- val rest = wRes( jRDF.rest )
+ val first = wProp( jRDF.first )
+ val rest = wProp( jRDF.rest )
+ val nil = wRes( jRDF.nil )
}
object RDFS extends Vocabulary( jRDFS.getURI ) {
View
19 src/main/scala/net/croz/scardf/query/SparqlQ.scala
@@ -162,11 +162,26 @@ class ConstructQ( triplets: (Any, Any, Any)* ) extends SparqlQ[ConstructQ] {
}
class PTreeConstructQ( ptree: PredicateTree ) extends SparqlQ[PTreeConstructQ] {
+ var lang: Lang = null
+ var langVars = List[Any]()
+
+ def filter( lang: Lang, qv: Any* ) = {
+ this.lang = lang
+ this.langVars = qv.toList
+ }
+
+ def constructFilter =
+ if ( langVars.isEmpty ) ""
+ else {
+ "FILTER (" + langVars.map{rendering(_)} + ") "
+ }
+
def from( anchor: Res ) = {
- var constructions, required, optionals = new StringBuffer()
+ var constructions = new StringBuffer()
val allTriplets = TripletFactory tripletsFrom ptree.growTemplateFrom( anchor ).model
appendTriplets( constructions, allTriplets: _* )
- val query = "CONSTRUCT { " + constructions + "} WHERE { " + constructions + "}"
+ val query = "CONSTRUCT { " + constructions + "} WHERE { " + constructions + " " +
+ constructFilter + "}"
val markStart = System.currentTimeMillis
val result = Model( execution( anchor.model, query ).execConstruct )
log info "Span construction took " + (System.currentTimeMillis - markStart) + " ms"
View
2  src/main/scala/org/scardf/augmentation.scala
@@ -52,7 +52,7 @@ abstract class PredAugmenter( pred: UriRef ) extends Augmenter {
case _ => false
} map { t => {
val ( p, o ) = augment( t.obj(g) )
- Triple( t.sub, p, o )
+ Triple( t.subj, p, o )
} }
}
View
6 src/main/scala/org/scardf/build.scala
@@ -23,6 +23,10 @@ case class Branch( root: SubjectNode, assignments: Pair[ UriRef, Twig ]* ) exten
override def values = Set( root )
+ /** Creates a new branch with the same root and some additional assignments */
+ def ++( additional: Pair[ UriRef, Twig ]* ) =
+ new Branch( root, assignments ++ additional: _* )
+
def toGraph = Graph( triples )
def rend = root + ": " + assignments
@@ -30,7 +34,7 @@ case class Branch( root: SubjectNode, assignments: Pair[ UriRef, Twig ]* ) exten
object Branch {
- implicit def toBranch( t: Triple ) = Branch( t.sub, t.pred -> ObjSet( t.obj ) )
+ implicit def toBranch( t: Triple ) = Branch( t.subj, t.pred -> ObjSet( t.obj ) )
def of( root: SubjectNode, assignments: Seq[ Pair[ UriRef, Twig ] ] ) =
Branch( root, assignments: _* )
View
10 src/main/scala/org/scardf/converters.scala
@@ -1,6 +1,6 @@
package org.scardf
-import org.joda.time.LocalDate
+import org.joda.time.{LocalDate, DateTime}
import org.joda.time.format.ISODateTimeFormat.{date => IsoFormat}
/**
@@ -52,6 +52,9 @@ extends NodeBagConverter[NodeBag] {
def apply( bag: NodeBag ) = NodeBag( bag.nodes filter{ n => ffn( n(bag.graph) ) }, bag.graph )
}
+/**
+ * Filter factory object.
+ */
object having {
def apply( pred: UriRef ) = new NodeFilter( _ match {
case gn: GraphNode => !(gn/pred).isEmpty
@@ -112,6 +115,8 @@ class TypeNodeConverter[T]( typename: String, typeUri: UriRef, fn: String => T )
case PlainLiteral( lf, _ ) => try { fn(lf) } catch { case e => throwException( l ) }
case _ => throwException( l )
}
+
+ def pfn( f: T => Boolean ): Literal => Boolean = { l: Literal => f( convertLiteral(l) ) }
}
object NodeConverter {
@@ -181,4 +186,7 @@ object NodeConverter {
implicit val asLocalDate = new TypeNodeConverter[LocalDate](
"a date", XSD.date, IsoFormat.parseDateTime( _ ).toLocalDate
)
+ implicit val asDateTime = new TypeNodeConverter[DateTime](
+ "date and time", XSD.dateTime, IsoFormat.parseDateTime( _ )
+ )
}
View
43 src/main/scala/org/scardf/core.scala
@@ -29,6 +29,13 @@ sealed abstract case class Node() extends TermPlace {
}
object Node {
+ /**
+ * Constructs a node from given value.
+ * <li>for a Node, returns it</li>
+ * <li>for a GraphNode, returns its node</li>
+ * <li>for a String, Int, Long, BigInt, BigDecimal, Boolean, LocalDate, returns it as a typed literal</li>
+ * <li>for other values, throws an IllegalArgumentException</li>
+ */
def from( a: Any ): Node = {
import Literal._
a match {
@@ -41,9 +48,33 @@ object Node {
case d: BigDecimal => toTypedLiteral( d )
case b: Boolean => toTypedLiteral( b )
case ld: LocalDate => toTypedLiteral( ld )
- case x => throw new RuntimeException( "Cannot convert " + x + " to Node" )
+ case x: AnyRef => throw new IllegalArgumentException( "Cannot convert " + x + " of " + x.getClass + " to Node" )
+ case x => throw new IllegalArgumentException( "Cannot convert " + x + " to Node" )
}
}
+
+ /**
+ * Checks if given node matches given template (any object).
+ * <li>every node matches object Node</li>
+ * <li>every literal node matches object Literal</li>
+ * <li>every subject node matches object SubjectNode</li>
+ * <li>every blank node matches object Blank</li>
+ * <li>if template is a node, parameters are checked for equality</li>
+ * <li>if template is a graph node, its node is checked for equality</li>
+ * <li>if template is function of Node to Boolean, this function is applied to tested node</li>
+ * <li>in all other cases, a node is constructed from the template object, and this is compared to the tested node</li>
+ */
+ def matches( template: Any, n: Node ): Boolean = template match {
+ case Node => true
+ case Literal => n.isLiteral
+ case SubjectNode => !n.isLiteral
+ case UriRef => !n.isBlank && !n.isLiteral
+ case Blank => n.isBlank
+ case m: Node => m == n
+ case gn: GraphNode => gn.node == n
+ case fn: Function[Node, Boolean] => fn( n )
+ case v => (Node from v) == n
+ }
}
/**
@@ -74,6 +105,16 @@ case class UriRef( uri: String ) extends SubjectNode with NodeToBagConverter {
def ? = PredicateTree.opt( this -> PredicateTree.empty )
override def rend = "<" + uri + ">"
+
+ def canEqual(other: Any): Boolean = other.isInstanceOf[UriRef]
+
+ override def equals(other: Any): Boolean =
+ other match {
+ case that: UriRef => (that canEqual this) && this.uri == that.uri
+ case _ => false
+ }
+
+ override def hashCode = uri.hashCode
override val toString = rend
}
View
99 src/main/scala/org/scardf/graph.scala
@@ -1,6 +1,6 @@
package org.scardf
-import scala.collection.mutable.{Set => MSet}
+import collection.mutable.{Set => MSet, Map => MMap}
trait Mutable
@@ -8,6 +8,16 @@ object Graph {
def apply() = new SetGraph( Set.empty[Triple] )
def apply( triples: Set[Triple] ): SetGraph = new SetGraph( triples )
def build( branches: Branch* ): SetGraph = branches.map{ _.toGraph }.foldLeft( Graph() ){ _++_ }
+
+ /**
+ * NOT IMPLEMENTED!
+ */
+ def mapping( g1: Set[Triple], g2: Set[Triple] ): Option[Map[Blank, Blank]] = {
+ val s1 = MSet() ++ g1
+ val s2 = MSet() ++ g2
+
+ Some(Map())
+ }
}
trait Graph {
@@ -21,21 +31,20 @@ trait Graph {
/**
* Two graphs are isomorphic if there is a mapping
- * between blank nodes in the graphs which makes two graph equal.
+ * between blank nodes in the graphs which makes the two graphs equal.
* NOT FULLY IMPLEMENTED!
*/
def =~( that: Graph ): Boolean = {
if ( this.size != that.size ) return false
+ val blankCount = this.blankNodes.toSeq.size
+ if ( blankCount != that.blankNodes.toSeq.size ) return false
+ if ( blankCount == 0 ) return true
val (thisBti, thisNbti) = triples partition{ _.hasBlankNode }
val (thatBti, thatNbti) = that.triples partition{ _.hasBlankNode }
val List( thisBt, thisNbt, thatBt, thatNbt ) =
List( thisBti, thisNbti, thatBti, thatNbti ) map { i => Set( i.toSeq: _* ) }
if ( thisNbt != thatNbt ) return false
- val blankCount = this.blankNodes.toSeq.size
- if ( blankCount != that.blankNodes.toSeq.size ) return false
- if ( blankCount == 0 ) return true
- // probably isomorphic, but not sure: return true for now
- true
+ Graph.mapping( thisBt, thatBt ).isDefined
}
def contains( t: Triple ): Boolean
@@ -43,16 +52,25 @@ trait Graph {
def /( n: SubjectNode ) = GraphNode( n, this )
def bagOf( vals: Any* ) = new NodeBag( vals map { Node from _ } toList, this )
def /- = NodeBag( subjects.toList, this )
- def /-/( nc: NodeToBagConverter ): NodeBag = /-/( NodeConverter.toNodeBagConverter(nc) )
+ def /-/( nc: NodeToBagConverter ): NodeBag = nc match {
+ // optimized for explicit predicates
+ case pred: UriRef => new NodeBag( triplesLike( Node, pred, Node ).toList.map( _.obj ), this )
+ case _ => /-/( NodeConverter.toNodeBagConverter(nc) )
+ }
def /-/[T]( bc: NodeBagConverter[T] ): T = (/-)/bc
- def subjects: Set[SubjectNode] = Set() ++ triples map { _.sub }
+ def subjects: Set[SubjectNode] = Set() ++ triples map { _.subj }
def objects: Set[Node] = Set() ++ triples map { _.obj }
def nodes = subjects ++ objects
def blankNodes: Iterable[Blank] = nodes filter { _.isBlank } map { _.asInstanceOf[Blank] }
- def filterT( pf: PartialFunction[Triple, Boolean] ) =
- Graph( Set() ++ triples filter { pf orElse {case _ => false} } )
+ def triplesMatching( pf: PartialFunction[Triple, Boolean] ): Iterable[Triple] =
+ triples filter{ pf orElse {case _ => false} }
+
+ def triplesLike( sp: Any, pp: Any, op: Any ): Iterable[Triple] = {
+ import Node.matches
+ triplesMatching { case Triple( s, p, o ) => matches( sp, s ) && matches( pp, p ) && matches( op, o ) }
+ }
/**
* Optional query engine available for querying this graph.
@@ -61,8 +79,8 @@ trait Graph {
def renderIn( sf: SerializationFormat ): Serializator = sf match {
case NTriple => new Serializator() {
- override def writeTo( w: java.io.Writer ) = null
- override def asString = triples.map{ _.rend }.mkString( "", "\n", "" )
+ override def writeTo( w: java.io.Writer ) = w write asString
+ override def asString = triples.map{ _.rend }.mkString( "\n" )
}
case _ => throw new UnsupportedOperationException()
}
@@ -72,22 +90,73 @@ trait Graph {
}
class SetGraph( tset: Set[Triple] ) extends Graph {
+ val index = new NodeIndex( tset )
+
def triples = tset
def +( t: Triple ): SetGraph = new SetGraph( Set( t ) ++ tset )
def ++( ts: Iterable[Triple] ) = new SetGraph( tset ++ ts )
override def ++( g: Graph ): SetGraph = this ++ g.triples
override def contains( t: Triple ) = tset contains t
+
+ override def triplesLike( sp: Any, pp: Any, op: Any ): Iterable[Triple] = {
+ import Node.matches
+ val tt = Set.empty ++ index( 1, sp ) ++ index( 2, pp ) ++ index( 3, op )
+ tt filter {
+ case Triple( s, p, o ) => matches( sp, s ) && matches( pp, p ) && matches( op, o )
+ case _ => false
+ }
+ }
}
class MutableSetGraph() extends Graph with Mutable {
val mset = MSet[Triple]()
+ val index = new NodeIndex()
+
def triples = mset
- def +( t: Triple ): MutableSetGraph = { mset += t; this }
- def ++( ts: Iterable[Triple] ): MutableSetGraph = { mset ++= ts; this }
+
+ def +( t: Triple ): MutableSetGraph = {
+ mset += t
+ index store t
+ this
+ }
+
+ def ++( ts: Iterable[Triple] ): MutableSetGraph = {
+ mset ++= ts
+ ts foreach { index store _ }
+ this
+ }
+
override def ++( g: Graph ): MutableSetGraph = this ++ g.triples
override def contains( t: Triple ) = mset contains t
}
+class NodeIndex {
+ type IndexMap = MMap[Node, MSet[Triple]]
+ def newIndexMap = MMap[Node, MSet[Triple]]()
+ val map = Map(1 -> newIndexMap, 2 -> newIndexMap, 3 -> newIndexMap )
+
+ def this( it: Iterable[Triple] ) = {
+ this()
+ it foreach { store }
+ }
+
+ def apply( pos: Int, p: Any ): Iterable[Triple] = p match {
+ case n: Node => triples( pos, n )
+ case _ => Nil
+ }
+
+ def store( t: Triple ) = {
+ update( 1, t.subj, t )
+ update( 2, t.pred, t )
+ update( 3, t.obj, t )
+ }
+
+ private[this] def update( pos: Int, n: Node, t: Triple ) =
+ map( pos ).getOrElseUpdate( n, MSet[Triple]() ) + t
+
+ def triples( pos: Int, n: Node ) = map( pos ).getOrElse( n, MSet[Triple]() )
+}
+
abstract class Serializator {
var bindings: Map[String, String] = Map()
View
31 src/main/scala/org/scardf/graphnode.scala
@@ -4,7 +4,7 @@ import scala.collection.mutable.{Set => MSet}
case class GraphNode( node: SubjectNode, graph: Graph ) extends NodeFromGraph {
override def /( ur: UriRef ) =
- NodeBag( graph.triples.filter{ t => t.sub == node && t.pred == ur }.map{ _.obj }.toList, graph )
+ NodeBag( graph.triplesLike( node, ur, Node ).map{ _.obj }.toList, graph )
def /[T]( nbc: NodeBagConverter[T] ): T = graph.bagOf( node )/nbc
@@ -12,16 +12,29 @@ case class GraphNode( node: SubjectNode, graph: Graph ) extends NodeFromGraph {
def -( poPairs: Pair[ UriRef, Any ]* ) = node -( poPairs: _* )
- def has( a: Pair[ UriRef, Any ] ) = a match {
+ /**
+ * Does node has given assignment in its graph?
+ * has( null -> _ ) throws an IllegalArgumentException.
+ * has( p -> null ) always yields true, for a not-null p.
+ * Options are treated specially: has( p -> None ) returns true iff there are
+ * NO valuesOf p in graph; has( p -> Some(o) ) is reduced to has( p -> o ).
+ * @see #valuesOf
+ */
+ def has( a: Pair[ UriRef, Any ] ): Boolean = a match {
+ case (null, _) => throw new IllegalArgumentException( "GraphNode.has requires predicate" )
+ case (_, null) => true
case (p, None) => valuesOf( p ).isEmpty
- case _ => graph contains Triple( node, a._1, Node from a._2 )
+ case (p, Some( o )) => has( p -> o )
+ case (p, o) => graph contains Triple( node, p, Node from o )
}
+ /**
+ * Iterable of all object nodes in this graph from triples
+ * containing this node as subject and given UriRef as predicate.
+ * @see #node
+ */
def valuesOf( predicate: UriRef ): Iterable[Node] =
- graph.triples filter {
- case Triple( `node`, `predicate`, o ) => true
- case _ => false
- } map { _.obj }
+ graph.triplesLike( node, predicate, Node ) map { _.obj }
/**
* Subgraphed node N in G is the same N in another graph S which is a subgraph of G
@@ -39,10 +52,10 @@ case class GraphNode( node: SubjectNode, graph: Graph ) extends NodeFromGraph {
println( subgraph.rend, covered )
if ( covered contains this.node ) return
else covered += this.node
- val outlinks = graph.filterT{ case Triple( this.node, _, _ ) => true }.triples
+ val outlinks = graph.triplesLike( this.node, Node, SubjectNode )
val connectedNodes = MSet[GraphNode]()
for ( s <- outlinks ) {
- if ( !s.obj.isLiteral ) connectedNodes += s.obj( graph ).asInstanceOf[GraphNode]
+ connectedNodes += s.obj( graph ).asInstanceOf[GraphNode]
subgraph + s
}
connectedNodes map { _.spreadTo( subgraph, covered ) }
View
24 src/main/scala/org/scardf/jena/jena-graph.scala
@@ -10,6 +10,28 @@ class JenaGraph( private val m: Model ) extends Graph {
def triples = new JenaTripleIterator( m.listStatements ).toList
+ override def triplesLike( sp: Any, pp: Any, op: Any ): Iterable[Triple] = {
+ import Node.matches
+ val tt = new JenaTripleIterator( m.listStatements(
+ sp match {
+ case n: SubjectNode => resource( n )
+ case _ => null
+ },
+ pp match {
+ case n: UriRef => property( n )
+ case _ => null
+ },
+ op match {
+ case n: Node => rdfnode( n )
+ case _ => null
+ }
+ ) )
+ tt.filter{
+ case Triple( s, p, o ) => matches( sp, s ) && matches( pp, p ) && matches( op, o )
+ case _ => false
+ }.toList
+ }
+
def contains( t: Triple ) = m contains statement( t )
override def +( t: Triple ) = {
@@ -27,7 +49,7 @@ class JenaGraph( private val m: Model ) extends Graph {
override def queryEngineOpt = Some( new JenaArq( m ) )
def statement( t: Triple ): Statement =
- m.createStatement( resource( t.sub ), property( t.pred ), rdfnode( t.obj ) )
+ m.createStatement( resource( t.subj ), property( t.pred ), rdfnode( t.obj ) )
def resource( sn: SubjectNode ) = sn match {
case b: Blank => m createResource new AnonId( b.id )
View
7 src/main/scala/org/scardf/jena/jena-query.scala
@@ -34,7 +34,12 @@ case class QSolution( jSolution: QuerySolution, m: Model ) {
*/
def get( key: String ) = {
val solution = jSolution.get( key )
- if ( solution == null ) None else Some( Node from solution )
+ if ( solution == null ) None else Some( converted( solution ) )
+ }
+
+ def converted( jenaX: Any ) = jenaX match {
+ case jnode: RDFNode => Jena.node( jnode )
+ case x => Node from x
}
/**
View
26 src/main/scala/org/scardf/query.scala
@@ -43,10 +43,25 @@ extends Tuple3[TermPlace, TermPlace, TermPlace](s, p, o)
lazy val rend = s.rend + " " + p.rend + " " + o.rend + " ."
}
+case class TemplateGraph( v: QVar, ttriples: Iterable[TemplateTriple] ) {
+ def rend = ttriples map {_.rend} mkString "\n"
+
+ private def queryResult( dg: Graph ) = {
+ val selectQ = "SELECT " + v.rend + " WHERE {" + rend + "}"
+ val qresult = dg.queryEngineOpt.get.select(selectQ)
+ println( selectQ, qresult )
+ qresult
+ }
+
+ def findIn( dg: Graph ): Node = queryResult(dg)(0)(v)
+ def findAllIn( dg: Graph ): List[Node] = queryResult(dg) map { _.apply(v) }
+}
+
object TemplateFactory {
- def templateFrom( g: Graph ): Iterable[TemplateTriple] = {
+ def apply( assignments: Pair[Blank, QVar]* ) = {
val tf = new TemplateFactory
- g.triples map{ tf( _ ) }
+ tf.varMap ++ assignments
+ tf
}
}
@@ -58,7 +73,12 @@ class TemplateFactory {
case other => other
}
- def apply( t: Triple ) = TemplateTriple( replaced( t.sub ), t.pred, replaced( t.obj ) )
+ def apply( t: Triple ): TemplateTriple = TemplateTriple( replaced( t.subj ), t.pred, replaced( t.obj ) )
+
+ def apply( g: Graph ): TemplateGraph = varMap.toList match {
+ case List( Pair( _, v ) ) => TemplateGraph( v, g.triples map apply )
+ case _ => null //TODO ???
+ }
}
trait QueryEngine {
View
8 src/main/scala/org/scardf/triple.scala
@@ -1,10 +1,10 @@
package org.scardf
-case class Triple( sub: SubjectNode, pred: UriRef, obj: Node )
-extends Tuple3[SubjectNode, UriRef, Node]( sub, pred, obj )
+case class Triple( subj: SubjectNode, pred: UriRef, obj: Node )
+extends Tuple3[SubjectNode, UriRef, Node]( subj, pred, obj )
{
- lazy val rend = sub.rend + " " + pred.rend + " " + obj.rend + " ."
-
+ lazy val rend = subj.rend + " " + pred.rend + " " + obj.rend + " ."
+
lazy val hasBlankNode = this match {
case Triple( b: Blank, _, _ ) => true
case Triple( _, _, b: Blank ) => true
View
2  src/main/scala/org/scardf/typedpredicates.scala
@@ -8,7 +8,7 @@ import NodeConverter._
* Use method {#v} to create an appropriate {NodeToValueConverter}
* (as UriRefs are {NodeToBagConverter}s).
*/
-case class Property[T]( override val uri: String )( implicit nc: NodeToValueConverter[T] )
+case class Property[T]( override val uri: String )( implicit val nc: NodeToValueConverter[T] )
extends UriRef( uri ) {
/**
* Applies this predicate and node-to-value converter.
View
3  src/main/scala/org/scardf/vocabulary.scala
@@ -26,7 +26,8 @@ case object XSD extends Vocabulary( "http://www.w3.org/2001/XMLSchema#" ) {
}
case object RDF extends Vocabulary( "http://www.w3.org/1999/02/22-rdf-syntax-ns#" ) {
- val Type = RDF÷"type"
+ val Type = prop( "type" )
+ val ID = RDF÷"ID"
val nil = RDF÷"nil"
val first = RDF÷"first"
val rest = RDF÷"rest"
View
2  src/test/scala/net/croz/scardf/QuerySpecs.scala
@@ -79,7 +79,7 @@ object QuerySpecs extends Specification with specs.RdfMatchers {
Map( person -> bob ),
Map( person -> jane, spouse -> john ),
Map( person -> john, spouse -> jane )
- )
+ )
}
"ask queries" in {
Sparql ask( (john, Likes, Science) ) in data must_== true
View
6 src/test/scala/net/croz/scardf/ScardfSpecs.scala
@@ -29,7 +29,7 @@ object ScardfSpecs extends Specification {
}
}
"Constructed graph" should {
- implicit val model = new Model() withPrefix "example:"
+ implicit val model = new Model() //withPrefix "example:"
import PeopleVocabulary._
val jdoe = Res( "jdoe" ) a Person state(
Name -> Anon(
@@ -73,8 +73,8 @@ object ScardfSpecs extends Specification {
(jdoe/Children/asRdfList).toList must_== List( Res( "anna" ), Res( "bob" ) )
}
"sparql query heighest" in {
- val selectHeighest = Sparql select 'person where( ('person, Height, 'h) ) orderBy desc( 'h ) limit 1
- val results = selectHeighest from model
+ val selectHighest = Sparql select 'person where( ('person, Height, 'h) ) orderBy desc( 'h ) limit 1
+ val results = selectHighest from model
results.solutions must_== List( Map( QVar( "person" ) -> jdoe ) )
}
"sparql query select X" in {
View
10 src/test/scala/net/croz/scardf/example_data.scala
@@ -25,22 +25,22 @@ object FamilyVocabulary extends Vocabulary( "http://family.eg#" ) {
private val aMale = IsMale -> true
private val aFemale = IsMale -> false
- val anna = Res( "anna" ) a Person state(
+ val anna = pRes( "anna" ) a Person state(
Name -> Anon( Given -> "Anna" ),
aFemale, Birthday -> "2004-04-14", Height -> 107,
Likes -> Swimming
)
- val bob = Res( "bob" ) a Person state(
+ val bob = pRes( "bob" ) a Person state(
Name -> Anon( Given -> "Bob" ),
aMale, Birthday -> "2007-05-18", Height -> 87
)
- val john = Res( "jdoe" ) a Person state(
+ val john = pRes( "jdoe" ) a Person state(
Name -> Anon( Given -> "John" ),
aMale, Birthday -> "1977-07-27", Height -> 167,
Likes -> ( Swimming, Science ),
- Children -> RdfList( anna, bob ), Spouse -> Res( "jane" )
+ Children -> RdfList( anna, bob ), Spouse -> pRes( "jane" )
)
- val jane = Res( "jane" ) a Person state(
+ val jane = pRes( "jane" ) a Person state(
Name -> Anon( Given -> "Jane" ),
aFemale, Birthday -> "1976-06-26", Height -> 150,
Likes -> Swimming,
View
6 src/test/scala/org/scardf/converter.spec.scala
@@ -32,14 +32,16 @@ object ConverterSpecs extends Specification {
".option" in {
g/bob/likes.option must_== None
}
- ".set" in {
+ "with .n modifier, get node" in {
g/anna/likes.n must_== swimming
}
"with .v modifier, convert node to value" in {
g/john/height.v must_== 167
}
- "convert bag to bag" in {
+ "list all values for fixed predicate" in {
g/-/height must_== g.bagOf( 99, 107, 150, 167 )
+ }
+ "list all values for fixed predicate, multiple values" in {
g/-/likes must_== g.bagOf( swimming, swimming, swimming, science )
}
"distinct filter" in {
View
22 src/test/scala/org/scardf/overview.spec.scala
@@ -63,5 +63,27 @@ object PrimerSpecs extends Specification {
familyMembers/having( weight -> None ) must_== familyMembers
}
}
+ "triple matching" in {
+ val g = Doe.graph
+ "pattern matching" in {
+ g.triples filter { _ match {
+ case Triple( `anna`, `height`, _ ) => true
+ case _ => false
+ } }
+ g.triplesMatching {
+ case Triple( `anna`, `height`, _ ) => true
+ }.toList must_== List( Triple( anna, height, Node from 107 ) )
+ g.triplesMatching {
+ case Triple( _, `height`, h: Literal ) => asInt(h) < 100
+ }.map{ _.subj }.toList must_== List( bob )
+ }
+ "triplesLike with Node placeholder" in {
+ g.triplesLike( anna, height, Node ).toList.size must_== 1
+ g.triplesLike( anna, height, Node ).toList must_== List( Triple( anna, height, Node from 107 ) )
+ }
+ "triplesLike with a closure" in {
+ g.triplesLike( Node, height, { h: Literal => asInt(h) < 100 } ).map{ _.subj }.toList must_== List( bob )
+ }
+ }
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.