Soprano 3 API Design

General Goals

  • Provide good transaction support based on a Repository/RepositoryConnection approach
    Respository is a base class created by the backend plugins
    RepositoryConnection is basically one transaction object created by the Repository
    Model is an abstract interface which is inherited by RepositoryConnection, Graph, and SparqlEndpoint
  • Allow backends to store native data in Node
  • Allow pooled Nodes for performance
  • Have queryflags which are used in all iterator methods like so:
    executeQuery( query, flags = noFlags )
    where flags is at least "EnableInference"
  • No need for queryLanguage flag in executeQuery anymore. We never used anything else than SPARQL.
  • New feature flags Transactions and Inference (Problem: what kind of inference?)
  • Enable and disable auto-commiting on the RepositoryConnection. See the Virtuoso tip regarding SPARUL updates.
  • Move everything into the Soprano3 namespace and soprano3/Soprano3 include paths to allow parallel installation of soprano 2 and 3 (we need 2 for bw comp of kdelibs)
  • Better async API which can be used with all repositories in some way. Then async backends could be used directly instead of wrapping in a thread.
  • Custom Repository configuraton method which allows finer grained configuration even after creating the repo. Soprano 2 only has the backend options which allow configuration at creation time. It would be more powerful to allow configuration later on via a similar system. That could even be used to configure inference support in Virtuoso.
  • Make Statement destructor non-virtual
  • Use Q_TYPE_INFO for Node, Statement, BindingSet for improved performance with Qt container classes.
  • More powerful Parser and Serializer design where the plugins create instances of the parser or serializer very much like Backend plugins create Models now. This allows for clients to have their own dedicated object which they can configure. For example with methods like addPrefix in the serializer. The alternative is to make the pluginmanager more powerful and let it handle parser, serializer, and model/repository creation. That way we avoid the additional overhead of the factory methods. This, however, is less powerful again since certain plugins might return different objects based on the required configuration/serialization.
  • Idea about iterators: we could have Iterator.toStatementIterator() and Iterator.isStatementIterator() and friends. Then we could return a plain Iterator from executeQuery and let the client cast accordingly. The same could be done for Node: Resource, Literal, and BlankNode as child classes to Node just like Nepomuk::Query::Term is done. Internally we do that anyway already.
  • Have API to create a unique URI - this is complicated as a URI can only be unique if we immediately create a statement with it. Thus, the question is how this can be done, maybe a dedicated type of node?


  • New NativeNodeData class...
  • Node::pooledNode() method....


  • Repository + RepositoryConnection...

Open Issues

  • Currently Model provides convenience methods for adding, removing statements, and testing their existance. These include addStatement, removeStatement, or containsStatement. These methods are non-virtual. This is nice but has one major problem. Imagine a subclass reimplements addStatement and then calls addStatement to call the parent class implementation. This will result in the reimplemented method to be called instead of the parent one since the addStatement variant using Nodes is calling the virtual one -> endless loop.
    I see two ways to solve this:
    1. do not provide convenience methods but a fully inline wrapper class which provides those. Disadvatage: one always needs to instanciate this class.
    2. Go a differnt way with RepositoryConnection: make it backend-based as the iterators are. Let Repository::createConnection return a copy of a RepositoryConnection which is explicetely shared internally.
  • What about const'ness of Model/RepositoryConnection methods? Currently read-only methods like containsStatement are const while others like addStatement are not. However, executeQuery is const. At the time this seems reasonable since none of the backends supported SPARUL. Virtuoso, however, does, and one can change everything using a query. const'ness of the method does not make much sense anymore.
    Thus, the question is: should we simply make the query-method non-const?