Viewing file: _sqlobject.py (11.68 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
from __future__ import generators
__metaclass__ = type
import logging _logger = logging.getLogger("rdflib.store._sqlobject")
import re _literal = re.compile(r'''"(?P<value>[^@&]*)"(?:@(?P<lang>[^&]*))?(?:&<(?P<datatype>.*)>)?''')
from urllib import quote, unquote
from rdflib.store import Store from rdflib.Literal import Literal from rdflib.URIRef import URIRef from rdflib.BNode import BNode from rdflib.exceptions import ContextTypeError
from rdflib.compat import rsplit
import sqlobject from sqlobject import *
LITERAL = 0 URI = 1 NO_URI = 'uri://oops/' Any = None
class BaseObject(sqlobject.SQLObject):
_lazyUpdate = True _cacheValues = False
class Literals(BaseObject):
hash = IntCol(notNull=1) value = StringCol(notNull=1, validator=validators.String(strip_spaces=1)) hashIndex = DatabaseIndex('hash')
class Namespaces(BaseObject):
hash = IntCol(notNull=1) value = StringCol(length=255, notNull=1, validator=validators.String(strip_spaces=1)) hashIndex = DatabaseIndex('hash')
class PrefixNamespace(BaseObject):
prefix = StringCol(length=255, notNull=1, validator=validators.String(strip_spaces=1)) ns = StringCol(length=255, notNull=1, validator=validators.String(strip_spaces=1)) prefixIndex = DatabaseIndex('prefix') nsIndex = DatabaseIndex('ns') prefixNsIndex = DatabaseIndex('ns', 'prefix')
class Resources(BaseObject):
hash = IntCol(notNull=1) ns = IntCol(notNull=1) name = StringCol(length=255, notNull=1, validator=validators.String(strip_spaces=1)) hashIndex = DatabaseIndex('hash') nsIndex = DatabaseIndex('ns') nameIndex = DatabaseIndex('name') nsNameIndex = DatabaseIndex('ns', 'name') hashNsNameIndex = DatabaseIndex('hash', 'ns', 'name')
class Triples(BaseObject):
subject = IntCol(notNull=1) predicate = IntCol(notNull=1) object = IntCol(notNull=1) objtype = IntCol(notNull=1, default=LITERAL)
subjectIndex = DatabaseIndex('subject') predicateIndex = DatabaseIndex('predicate') objectIndex = DatabaseIndex('object', 'objtype') subjectPredicateIndex = DatabaseIndex('subject', 'predicate') subjectObjectIndex = DatabaseIndex('subject', 'object', 'objtype') predicateObjectIndex = DatabaseIndex('predicate', 'object', 'objtype')
def splituri(uri): if uri.startswith('<') and uri.endswith('>'): uri = uri[1:-1] if uri.startswith('_'): uid = ''.join(uri.split('_')) return '_', uid if '#' in uri: ns, local = rsplit(uri, '#', 1) return ns + '#', local if '/' in uri: ns, local = rsplit(uri, '/', 1) return ns + '/', local return NO_URI, uri
def _fromkey(key): if key.startswith("<") and key.endswith(">"): key = key[1:-1].decode("UTF-8") if key.startswith("_"): key = ''.join(splituri(key)) return BNode(key) return URIRef(key) elif key.startswith("_"): return BNode(key) else: m = _literal.match(key) if m: d = m.groupdict() value = d["value"] value = unquote(value) value = value.decode("UTF-8") lang = d["lang"] or '' datatype = d["datatype"] return Literal(value, lang, datatype) else: msg = "Unknown Key Syntax: '%s'" % key raise Exception(msg)
def _tokey(term): if isinstance(term, URIRef): term = term.encode("UTF-8") if not '#' in term and not '/' in term: term = '%s%s' % (NO_URI, term) return '<%s>' % term elif isinstance(term, BNode): return '<%s>' % ''.join(splituri(term.encode("UTF-8"))) elif isinstance(term, Literal): language = term.language datatype = term.datatype value = quote(term.encode("UTF-8")) if language: language = language.encode("UTF-8") if datatype: datatype = datatype.encode("UTF-8") n3 = '"%s"@%s&<%s>' % (value, language, datatype) else: n3 = '"%s"@%s' % (value, language) else: if datatype: datatype = datatype.encode("UTF-8") n3 = '"%s"&<%s>' % (value, datatype) else: n3 = '"%s"' % value return n3 else: msg = "Unknown term Type for: %s" % term raise Exception(msg)
class SQLObject(Store):
context_aware = False __open = False _triples = Triples _literals = Literals _ns = Namespaces _prefix_ns = PrefixNamespace _resources = Resources tables = ('_triples', '_literals', '_ns', '_prefix_ns', '_resources')
def __init__(self): pass
def open(self, uri, create=True): if self.__open: return self.__open = True self.connection = connection = connectionForURI(uri) # useful for debugging # self.connection.debug = True for att in self.tables: table = getattr(self, att) table._connection = connection try: table.createTable(ifNotExists=create) except Exception, e: # TODO: should catch more specific exception _logger.warning(e) return 0
self.transaction = transaction = connection.transaction() for att in self.tables: table = getattr(self, att) table._connection = transaction return 1
def close(self): if not self.__open: raise ValueError, 'Not open' self.__open = False self.transaction.commit()
def _makeHash(self, value): # XXX We will be using python's hash, but it should be a database # hash eventually. return hash(value)
def _insertLiteral(self, value): v_hash = self._makeHash(value) lit = self._literals if not lit.select(lit.q.hash == v_hash).count(): lit(hash=v_hash, value=value) return v_hash
def _makeURIHash(self, value=None, namespace=None, local_name=None): if namespace is None and local_name is None: namespace, local_name = splituri(value) ns_hash = self._makeHash(namespace) rsrc_hash = self._makeHash((ns_hash, local_name)) return ns_hash, rsrc_hash
def _insertURI(self, value=None, namespace=None, local_name=None): if namespace is None and local_name is None: namespace, local_name = splituri(value) ns_hash, rsrc_hash = self._makeURIHash(value, namespace, local_name) ns = self._ns if not ns.select(ns.q.hash == ns_hash).count(): ns(hash=ns_hash, value=namespace) rsrc = self._resources if not rsrc.select(rsrc.q.hash == rsrc_hash).count(): rsrc(hash=rsrc_hash, ns=ns_hash, name=local_name) return rsrc_hash
def _insertTriple(self, s_hash, p_hash, o_hash, objtype=URI): trip = self._triples clause = AND(trip.q.subject == s_hash, trip.q.predicate == p_hash, trip.q.object == o_hash) if not trip.select(clause).count(): trip(subject=s_hash, predicate=p_hash, object=o_hash, objtype=objtype)
def tokey(self, obj): if isinstance(obj, (URIRef, BNode)): return URI, self._makeURIHash(_tokey(obj))[1] elif isinstance(obj, Literal): return LITERAL, self._makeHash(_tokey(obj)) elif obj is Any: return None, Any raise ValueError, obj
def insert(self, obj): if isinstance(obj, (URIRef, BNode)): return URI, self._insertURI(_tokey(obj)) elif isinstance(obj, Literal): return LITERAL, self._insertLiteral(_tokey(obj)) raise ValueError, obj
def add(self, (subject, predicate, object), context=None): """\ Add a triple to the store of triples. """ tokey = self.insert ts, s = tokey(subject) tp, p = tokey(predicate) to, o = tokey(object)
self._insertTriple(s, p, o, to)
def remove(self, (subject, predicate, object), context=None): tokey = self.tokey where_clause = ''
if subject is not Any: ts, s = tokey(subject) where_clause += 'subject = %s' % s if predicate is not Any: if where_clause: where_clause += ' AND ' tp, p = tokey(predicate) where_clause += 'predicate = %s' % p if object is not Any: if where_clause: where_clause += ' AND ' to, o = tokey(object) where_clause += 'object = %s AND objtype = %s' % (o, to)
trip = self._triples conn = trip._connection query = 'DELETE from %s' % conn.sqlrepr(trip.q) if where_clause: query += ' WHERE %s' % where_clause conn.query(query)
def triples(self, (subject, predicate, object), context=None): conn = self._triples._connection
tokey = self.tokey where_clause = '' if subject is not Any: ts, s = tokey(subject) where_clause += 'r1.hash = %s' % s if predicate is not Any: if where_clause: where_clause += ' AND ' tp, p = tokey(predicate) where_clause += 'r2.hash = %s' % p if object is not Any: if where_clause: where_clause += ' AND ' to, o = tokey(object) if to == URI: where_clause += 'r3.hash = %s' % o else: where_clause += 'l.hash = %s' % o
query = ("SELECT '<'||n1.value||r1.name||'>' AS subj, " "'<'||n2.value||r2.name||'>' AS pred, " "CASE WHEN t.objtype = %d " "THEN '<'||n3.value||r3.name||'>' " "ELSE l.value END AS obj, " "l.hash, r3.hash " "FROM resources r1, resources r2, " "namespaces n1, namespaces n2, triples t " "LEFT JOIN literals l ON t.object = l.hash " "LEFT JOIN resources r3 ON t.object = r3.hash " "LEFT JOIN namespaces n3 ON r3.ns = n3.hash " "WHERE t.subject = r1.hash AND " "r1.ns = n1.hash AND " "t.predicate = r2.hash AND " "r2.ns = n2.hash" % URI) if where_clause: query += ' AND %s' % where_clause query += ' ORDER BY subj, pred' for t in conn.queryAll(query): triple = _fromkey(t[0]), _fromkey(t[1]), _fromkey(t[2]) yield triple
def namespace(self, prefix): prefix = prefix.encode("utf-8") pns = self._prefix_ns res = pns.select(pns.q.prefix == prefix) if not res.count(): return None return iter(res).next().ns
def prefix(self, namespace): namespace = namespace.encode("utf-8") pns = self._prefix_ns res = pns.select(pns.q.ns == namespace) if not res.count(): return None return iter(res).next().prefix
def bind(self, prefix, namespace): if namespace[-1] == "-": raise Exception("??") pns = self._prefix_ns prefix = prefix.encode("utf-8") namespace = namespace.encode("utf-8") res = pns.select(AND(pns.q.ns == namespace, pns.q.prefix == prefix)) if not res.count(): pns(prefix=prefix, ns=namespace)
def namespaces(self): pns = self._prefix_ns for p in pns.select(): yield p.prefix, URIRef(p.ns)
def __len__(self): return self._triples.select().count()
|