#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pylint: disable-msg=C0103
################################################################################
# Copyright (c) 2006-2017 Franz Inc.
# All rights reserved. This program and the accompanying materials are
# made available under the terms of the MIT License which accompanies
# this distribution, and is available at http://opensource.org/licenses/MIT
################################################################################
from __future__ import absolute_import
from __future__ import unicode_literals
from past.builtins import basestring
from builtins import object
from future import standard_library
standard_library.install_aliases()
from ..exceptions import IllegalArgumentException
from ..model import URI, ValueFactory
from .repositoryconnection import RepositoryConnection
from ..vocabulary.xmlschema import XMLSchema
import re
[docs]class Repository(object):
"""
A repository contains RDF data that can be queried and updated. Access
to the repository can be acquired by opening a connection to it. This
connection can then be used to query and/or update the contents of the
repository.
Please note that a repository needs to be initialized before it can be
used and that it should be shut down before it is discarded/garbage
collected. Forgetting the latter can result in loss of data (depending
on the Repository implementation)!
"""
# Modes for Catalog.getRepository()
RENEW = 'RENEW'
ACCESS = 'ACCESS'
OPEN = 'OPEN'
CREATE = 'CREATE'
REPLACE = 'REPLACE'
[docs] def __init__(self, catalog, database_name, repository):
"""
Invoke through :meth:`~franz.openrdf.sail.allegrographserver.Catalog.getRepository`.
"""
self.mini_repository = repository
self.database_name = database_name
self.catalog = catalog
# system state fields:
self.value_factory = None
[docs] def getDatabaseName(self):
"""
Return the name of the database (remote triple store) that this repository is
interfacing with.
"""
return self.database_name
[docs] def getSpec(self):
"""
Return a session spec string for this repository.
See :meth:`~franz.openrdf.sail.allegrographserver.AllegroGraphServer.openSession`.
:return: A session spec.
:rtype: string
"""
mini = self.mini_repository
urlstart = re.match("^https?://", mini.url).group(0)
url = "<%s%s:%s@%s>" % (urlstart, mini.user, mini.password,
mini.url[len(urlstart):])
return url
[docs] def initialize(self):
"""
Initializes this repository. A repository must be initialized before
it can be used.
It is recommended to take advantage of the fact that repositories
are context managers and use the ``with`` statement to ensure that
:meth:`initialize` and :meth:`shutDown` are called:
.. code:: python
with catalog.getRepository() as repo:
# No need to call initialize or shutDown inside.
...
:return: ``self`` (to allow call chaining).
"""
# We've only kept this method for RDF4J compatibility, we do not actually
# need to do anything here.
return self
[docs] def registerDatatypeMapping(self, predicate=None, datatype=None, nativeType=None):
"""
Register an inlined datatype.
This allows some literals to be stored in an optimized form
on the server.
.. seealso::
http://franz.com/agraph/support/documentation/current/lisp-reference.html#ref-type-mapping
More detailed discussion of type mappings in the Lisp API documentation.
You must supply ``nativeType`` and either ``predicate`` or ``datatype``.
If ``predicate`` is supplied, then object arguments to triples with that
predicate will use an inlined encoding of type `nativeType` in their internal
representation on the server.
If ``datatype`` is supplied, then typed literal objects with a datatype matching
``datatype`` will use an inlined encoding of type `nativeType`.
Duplicated in the :class:`.RepositoryConnection` class for Python user convenience.
:param predicate: The URI of a predicate used in the triple store.
:param datatype: May be one of: ``XMLSchema.INT``, ``XMLSchema.LONG``,
``XMLSchema.FLOAT``, ``XMLSchema.DATE`` and ``XMLSchema.DATETIME``.
:param nativeType: may be ``int``, ``datetime``, or ``float``.
:type nativeType: string|type
"""
predicate = predicate.getURI() if isinstance(predicate, URI) else predicate
datatype = datatype.getURI() if isinstance(datatype, URI) else datatype
if nativeType is not None and not isinstance(nativeType, basestring):
nativeType=nativeType.__name__
def translate_inlined_type(the_type):
if the_type == 'int':
return XMLSchema.LONG.toNTriples()
if the_type == 'datetime':
return XMLSchema.DATETIME.toNTriples()
if the_type == 'time':
return XMLSchema.TIME.toNTriples()
if the_type == 'date':
return XMLSchema.DATE.toNTriples()
if the_type == "float":
return XMLSchema.DOUBLE.toNTriples()
if the_type == "bool":
return XMLSchema.BOOLEAN.toNTriples()
raise IllegalArgumentException("Unknown inlined type '%s'\n. Legal types are "\
"int, float, bool, datetime, time, and date." % the_type)
if predicate:
if not nativeType:
raise IllegalArgumentException("Missing 'nativeType' parameter in call to 'registerDatatypeMapping'")
xsdType = translate_inlined_type(nativeType)
self.mini_repository.addMappedPredicate("<%s>" % predicate, xsdType)
elif datatype:
xsdType = translate_inlined_type(nativeType or datatype)
self.mini_repository.addMappedType("<%s>" % datatype, xsdType)
[docs] def shutDown(self):
"""
Shuts the store down, releasing any resources that it keeps hold of.
Once shut down, the store can no longer be used.
It is recommended to take advantage of the fact that repositories
are context managers and use the ``with`` statement to ensure that
:meth:`initialize` and :meth:`shutDown` are called:
.. code:: python
with catalog.getRepository() as repo:
# No need to call initialize or shutDown inside.
...
"""
self.mini_repository = None
[docs] def isWritable(self):
"""
Checks whether this store is writable, i.e. if the data contained in
this store can be changed. The writability of the store is
determined by the writability of the Sail that this store operates
on.
"""
# TODO maybe remove this, it's nonsense in 4.0.
return True
[docs] def getConnection(self):
"""
Opens a connection to this store that can be used for querying and
updating the contents of the store. Created connections need to be
closed to make sure that any resources they keep hold of are released.
The best way to ensure this is to use a ``with`` statement:
.. code:: python
with repo.getConnection() as conn:
...
:return: A :class:`RepositoryConnection` object.
:rtype: RepositoryConnection
"""
return RepositoryConnection(self)
[docs] def getValueFactory(self):
"""
Return a ValueFactory for this store.
This is present for RDF4J compatibility, but in the Python API all ValueFactory
functionality has been duplicated or subsumed in the :class:`.RepositoryConnection` class.
It isn't necessary to manipulate the :class:`.ValueFactory` class at all.
:return: A ValueFactory instance.
:rtype: ValueFactory
"""
if not self.value_factory:
self.value_factory = ValueFactory(self)
return self.value_factory
def _set_bulk_mode(self, on):
self.mini_repository.setBulkMode(on)
def _get_bulk_mode(self):
return self.mini_repository.getBulkMode()
bulk_mode = property(
_get_bulk_mode, _set_bulk_mode,
doc="""Turn BulkMode on with True or off with False.
In bulk mode, all modifications to the triple-store are made without
writing to the transaction log. There is overhead to switching
in and out of bulk-mode, and it is a global repository state, so all
clients are affected.""")
def __enter__(self):
self.initialize()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
del exc_type, exc_val, exc_tb
self.shutDown()