Skip to content

Commit 7208cbd

Browse files
committed
Replace sql "INSERT" by sqlalchemy insert clause
1 parent 13f1bc3 commit 7208cbd

File tree

2 files changed

+118
-138
lines changed

2 files changed

+118
-138
lines changed

rdflib_sqlalchemy/SQLAlchemy.py

Lines changed: 110 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from rdflib.py3compat import PY3
1515
from rdflib.plugins.stores.regexmatching import REGEXTerm
1616
from sqlalchemy import Column, Table, MetaData, Index, types
17+
from sqlalchemy.sql import select
1718
from .termutils import REVERSE_TERM_COMBINATIONS
1819
from .termutils import TERM_INSTANTIATION_DICT
1920
from .termutils import constructGraph
@@ -272,6 +273,16 @@ def createTerm(
272273
store.otherCache[(termType, termString)] = rt
273274
return rt
274275

276+
class TermType(types.TypeDecorator):
277+
278+
impl = types.Text
279+
280+
def process_bind_param(self, value, dialect):
281+
if isinstance(value, (QuotedGraph, Graph)):
282+
return value.identifier
283+
else:
284+
return value
285+
275286

276287
class SQLGenerator(object):
277288

@@ -406,72 +417,67 @@ def normalizeTerm(self, term):
406417
else:
407418
return term.encode('utf-8')
408419

409-
def buildTypeSQLCommand(self, member, klass, context, storeId):
420+
def buildTypeSQLCommand(self, member, klass, context):
410421
"""
411422
Builds an insert command for a type table
412423
"""
413424
#columns: member,klass,context
414-
rt = "INSERT INTO %s_type_statements" % storeId + \
415-
" (member,klass,context,termComb) VALUES (%s, %s, %s,%s)"
416-
return rt, [
417-
self.normalizeTerm(member),
418-
self.normalizeTerm(klass),
419-
self.normalizeTerm(context.identifier),
420-
int(type2TermCombination(member, klass, context))]
425+
rt = self.tables['type_statements'].insert()
426+
return rt, {
427+
'member': member,
428+
'klass' : klass,
429+
'context': context.identifier,
430+
'termComb': int(type2TermCombination(member, klass, context))}
421431

422432
def buildLiteralTripleSQLCommand(
423-
self, subject, predicate, obj, context, storeId):
433+
self, subject, predicate, obj, context):
424434
"""
425435
Builds an insert command for literal triples (statements where the
426436
object is a Literal)
427437
"""
428438
triplePattern = int(
429439
statement2TermCombination(subject, predicate, obj, context))
430-
literal_table = "%s_literal_statements" % storeId
431-
command = "INSERT INTO %s " % literal_table + \
432-
"(subject,predicate,object,context,termComb,objLanguage," + \
433-
"objDatatype) VALUES (%s, %s, %s, %s, %s,%s,%s)"
434-
return command, [
435-
self.normalizeTerm(subject),
436-
self.normalizeTerm(predicate),
437-
self.normalizeTerm(obj),
438-
self.normalizeTerm(context.identifier),
439-
triplePattern,
440-
isinstance(obj, Literal) and obj.language or None,
441-
isinstance(obj, Literal) and obj.datatype or None]
440+
command = self.tables['literal_statements'].insert()
441+
values = {
442+
'subject': subject,
443+
'predicate': predicate,
444+
'object': obj,
445+
'context': context.identifier,
446+
'termComb': triplePattern,
447+
'objLanguage': isinstance(obj, Literal) and obj.language or None,
448+
'objDatatype': isinstance(obj, Literal) and obj.datatype or None
449+
}
450+
return command, values
451+
442452

443453
def buildTripleSQLCommand(
444-
self, subject, predicate, obj, context, storeId, quoted):
454+
self, subject, predicate, obj, context, quoted):
445455
"""
446456
Builds an insert command for regular triple table
447457
"""
448-
stmt_table = quoted and "%s_quoted_statements" % storeId \
449-
or "%s_asserted_statements" % storeId
458+
stmt_table = quoted and self.tables['quoted_statements'] \
459+
or self.tables['asserted_statements']
450460
triplePattern = statement2TermCombination(
451461
subject, predicate, obj, context)
462+
command = stmt_table.insert()
452463
if quoted:
453-
command = "INSERT INTO %s " % stmt_table + \
454-
"(subject,predicate,object,context,termComb," + \
455-
"objLanguage,objDatatype) VALUES " + \
456-
"(%s, %s, %s, %s, %s,%s,%s)"
457-
params = [
458-
self.normalizeTerm(subject),
459-
self.normalizeTerm(predicate),
460-
self.normalizeTerm(obj),
461-
self.normalizeTerm(context.identifier),
462-
triplePattern,
463-
isinstance(obj, Literal) and obj.language or None,
464-
isinstance(obj, Literal) and obj.datatype or None]
464+
params = {
465+
'subject': subject,
466+
'predicate': predicate,
467+
'object': obj,
468+
'context': context.identifier,
469+
'termComb' : triplePattern,
470+
'objLanguage': isinstance(obj, Literal) and obj.language or None,
471+
'objDatatype': isinstance(obj, Literal) and obj.datatype or None
472+
}
465473
else:
466-
command = "INSERT INTO %s " % stmt_table + \
467-
"(subject,predicate,object,context,termComb) " + \
468-
"VALUES (%s, %s, %s, %s, %s)"
469-
params = [
470-
self.normalizeTerm(subject),
471-
self.normalizeTerm(predicate),
472-
self.normalizeTerm(obj),
473-
self.normalizeTerm(context.identifier),
474-
triplePattern]
474+
params = {
475+
'subject': subject,
476+
'predicate': predicate,
477+
'object': obj,
478+
'context': context.identifier,
479+
'termComb': triplePattern
480+
}
475481
return command, params
476482

477483
def buildClause(
@@ -853,9 +859,6 @@ def close(self, commit_pending_transaction=False):
853859
"""
854860
FIXME: Add documentation!!
855861
"""
856-
pass
857-
#if commit_pending_transaction:
858-
# self.connection.commit()
859862
try:
860863
self.engine.close()
861864
except:
@@ -883,76 +886,56 @@ def destroy(self, configuration):
883886
# _logger.debug(
884887
# "Destroyed Close World Universe %s" % (self.identifier))
885888

886-
# Triple Methods
887-
def add(self, (subject, predicate, obj), context=None, quoted=False):
888-
""" Add a triple to the store of triples. """
889+
def __getBuildCommand(self, (subject, predicate, obj), context=None, quoted=False):
890+
891+
buildCommandType = None
889892
if quoted or predicate != RDF.type:
890893
# Quoted statement or non rdf:type predicate
891894
# check if object is a literal
892895
if isinstance(obj, Literal):
893896
addCmd, params = self.buildLiteralTripleSQLCommand(
894-
subject, predicate, obj, context, self._internedId)
897+
subject, predicate, obj, context)
898+
buildCommandType = 'literal'
895899
else:
896900
addCmd, params = self.buildTripleSQLCommand(
897-
subject, predicate, obj, context, self._internedId, quoted)
901+
subject, predicate, obj, context, quoted)
902+
buildCommandType = 'other'
898903
elif predicate == RDF.type:
899904
#asserted rdf:type statement
900-
addCmd, params = self.buildTypeSQLCommand(
901-
subject, obj, context, self._internedId)
905+
addCmd, params = self.buildTypeSQLCommand(subject, obj, context)
906+
buildCommandType = 'type'
907+
return buildCommandType, addCmd, params
908+
909+
910+
# Triple Methods
911+
def add(self, (subject, predicate, obj), context=None, quoted=False):
912+
""" Add a triple to the store of triples. """
913+
914+
_, addCmd, params = self.__getBuildCommand((subject, predicate, obj), context, quoted)
902915
with self.engine.connect() as connection:
903-
trans = connection.begin()
904916
try:
905-
self.executeSQL(addCmd, params, connection=connection)
906-
trans.commit()
917+
connection.execute(addCmd, params)
907918
except Exception, msg:
908-
_logger.debug("Add failed %s with commands %s" % (msg, addCmd))
909-
trans.rollback()
919+
_logger.debug("Add failed %s with commands %s params %s" % (msg, str(addCmd), repr(params)))
910920

911921
def addN(self, quads):
912-
literalTriples = []
913-
typeTriples = []
914-
otherTriples = []
915-
literalTripleInsertCmd = None
916-
typeTripleInsertCmd = None
917-
otherTripleInsertCmd = None
922+
923+
cmdTriplesDict = {
924+
}
925+
918926
for subject, predicate, obj, context in quads:
919-
if isinstance(context, QuotedGraph) or predicate != RDF.type:
920-
# Quoted statement or non rdf:type predicate
921-
# check if object is a literal
922-
if isinstance(obj, Literal):
923-
cmd, params = self.buildLiteralTripleSQLCommand(
924-
subject, predicate, obj, context, self._internedId)
925-
literalTripleInsertCmd = \
926-
literalTripleInsertCmd is not None \
927-
and literalTripleInsertCmd or cmd
928-
literalTriples.append(params)
929-
else:
930-
cmd, params = self.buildTripleSQLCommand(
931-
subject, predicate, obj, context, self._internedId,
932-
isinstance(context, QuotedGraph))
933-
otherTripleInsertCmd = \
934-
otherTripleInsertCmd is not None \
935-
and otherTripleInsertCmd or cmd
936-
otherTriples.append(params)
937-
elif predicate == RDF.type:
938-
#asserted rdf:type statement
939-
cmd, params = self.buildTypeSQLCommand(
940-
subject, obj, context, self._internedId)
941-
typeTripleInsertCmd = \
942-
typeTripleInsertCmd is not None \
943-
and typeTripleInsertCmd or cmd
944-
typeTriples.append(params)
945-
946-
self.executeSQL(literalTripleInsertCmd, literalTriples, paramList=True)
927+
buildCommandType, cmd, params = \
928+
self.__getBuildCommand((subject, predicate, obj), context, isinstance(context, QuotedGraph))
929+
930+
cmdTriple = cmdTripleDict.get(buildCommandType, {})
931+
cmdTriple.setdefault('cmd', cmd)
932+
cmdTriple.setdefault('params', []).append(params)
933+
947934
with self.engine.connect() as connection:
948935
trans = connection.begin()
949936
try:
950-
if literalTriples:
951-
self.executeSQL(literalTripleInsertCmd, literalTriples, paramList=True, connection=connection)
952-
if typeTriples:
953-
self.executeSQL(typeTripleInsertCmd, typeTriples, paramList=True, connection=connection)
954-
if otherTriples:
955-
self.executeSQL(otherTripleInsertCmd, otherTriples, paramList=True, connection=connection)
937+
for cmdTriple in cmdTripleDict.values():
938+
connection.execute(cmdTriple['cmd'], cmdTriple['params'])
956939
except Exception, msg:
957940
_logger.debug("AddN failed %s" % msg)
958941
trans.rollback()
@@ -1474,60 +1457,52 @@ def value(self, subject,
14741457
def bind(self, prefix, namespace):
14751458
""" """
14761459
with self.engine.connect() as connection:
1477-
trans = connection.begin()
14781460
try:
1479-
connection.execute(
1480-
"INSERT INTO %s_namespace_binds " +
1481-
"(prefix,uri) VALUES ('%s', '%s')" % (
1482-
self._internedId,
1483-
prefix,
1484-
namespace))
1485-
trans.commit()
1461+
ins = self.tables['namespace_binds'].insert().values(prefix=prefix, uri=namesapce)
1462+
connection.execute(ins)
14861463
except Exception, msg:
14871464
_logger.debug("Namespace binding failed %s" % msg)
1488-
trans.rollback()
14891465

14901466
def prefix(self, namespace):
14911467
""" """
14921468
with self.engine.connect() as connection:
1493-
res = connection.execute("SELECT prefix FROM %s_namespace_binds WHERE uri = '%s'" % (
1494-
self._internedId,
1495-
namespace))
1469+
nb_table = self.tables['namespace_binds']
1470+
s = select([nb_table.c.prefix]).where(nb_table.c.uri == namespace)
1471+
res = connection.execute(s)
14961472
rt = [rtTuple[0] for rtTuple in res.fetchall()]
1473+
res.close()
14971474
return rt and rt[0] or None
14981475

14991476
def namespace(self, prefix):
15001477
""" """
15011478
res = None
15021479
try:
15031480
with self.engine.connect() as connection:
1504-
res = connection.execute(
1505-
"SELECT uri FROM %s_namespace_binds WHERE prefix = '%s'" % (
1506-
self._internedId,
1507-
prefix))
1481+
nb_table = self.tables['namespace_binds']
1482+
s = select([nb_table.c.uri]).where(nb_table.c.prefix == prefix)
1483+
res = connection.execute(s)
15081484
except:
15091485
return None
15101486
rt = [rtTuple[0] for rtTuple in res.fetchall()]
1487+
res.close()
15111488
return rt and rt[0] or None
15121489

15131490
def namespaces(self):
15141491
""" """
15151492
with self.engine.connect() as connection:
1516-
res = connection.execute("SELECT prefix, uri FROM %s_namespace_binds;" % (
1517-
self._internedId))
1518-
rt = res.fetchall()
1519-
for prefix, uri in rt:
1493+
res = connection.execute(self.tables['namespace_binds'].select())
1494+
for prefix, uri in res.fetchall():
15201495
yield prefix, uri
15211496

15221497
def __create_table_definitions(self):
15231498
self.metadata = MetaData()
15241499
self.tables = {
15251500
'asserted_statements':
15261501
Table('%s_asserted_statements' % self._internedId, self.metadata,
1527-
Column('subject', types.Text, nullable=False),
1528-
Column('predicate', types.Text, nullable=False),
1529-
Column('object', types.Text, nullable=False),
1530-
Column('context', types.Text, nullable=False),
1502+
Column('subject', TermType, nullable=False),
1503+
Column('predicate', TermType, nullable=False),
1504+
Column('object', TermType, nullable=False),
1505+
Column('context', TermType, nullable=False),
15311506
Column('termcomb', types.Integer, nullable=False, key="termComb"),
15321507
Index("%s_A_termComb_index" % self._internedId, 'termComb'),
15331508
Index("%s_A_s_index" % self._internedId, 'subject'),
@@ -1537,9 +1512,9 @@ def __create_table_definitions(self):
15371512
),
15381513
'type_statements':
15391514
Table('%s_type_statements' % self._internedId, self.metadata,
1540-
Column('member', types.Text, nullable=False),
1541-
Column('klass', types.Text, nullable=False),
1542-
Column('context', types.Text, nullable=False),
1515+
Column('member', TermType, nullable=False),
1516+
Column('klass', TermType, nullable=False),
1517+
Column('context', TermType, nullable=False),
15431518
Column('termcomb', types.Integer, nullable=False, key="termComb"),
15441519
Index("%s_T_termComb_index" % self._internedId, 'termComb'),
15451520
Index("%s_member_index" % self._internedId, 'member'),
@@ -1548,10 +1523,10 @@ def __create_table_definitions(self):
15481523
),
15491524
'literal_statements':
15501525
Table('%s_literal_statements' % self._internedId, self.metadata,
1551-
Column('subject', types.Text, nullable=False),
1552-
Column('predicate', types.Text, nullable=False),
1553-
Column('object', types.Text),
1554-
Column('context', types.Text, nullable=False),
1526+
Column('subject', TermType, nullable=False),
1527+
Column('predicate', TermType, nullable=False),
1528+
Column('object', TermType),
1529+
Column('context', TermType, nullable=False),
15551530
Column('termcomb', types.Integer, nullable=False, key="termComb"),
15561531
Column('objlanguage', types.String(255), key="objLanguage"),
15571532
Column('objdatatype', types.String(255), key="objDatatype"),
@@ -1562,10 +1537,10 @@ def __create_table_definitions(self):
15621537
),
15631538
'quoted_statements':
15641539
Table("%s_quoted_statements" % self._internedId, self.metadata,
1565-
Column('subject', types.Text, nullable=False),
1566-
Column('predicate', types.Text, nullable=False),
1567-
Column('object', types.Text),
1568-
Column('context', types.Text, nullable=False),
1540+
Column('subject', TermType, nullable=False),
1541+
Column('predicate', TermType, nullable=False),
1542+
Column('object', TermType),
1543+
Column('context', TermType, nullable=False),
15691544
Column('termcomb', types.Integer, nullable=False, key="termComb"),
15701545
Column('objlanguage', types.String(255), key="objLanguage"),
15711546
Column('objdatatype', types.String(255), key="objDatatype"),

test/graph_case.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,19 @@ def testStoreLiterals(self):
300300
def testStoreLiteralsXml(self):
301301
bob = self.bob
302302
says = URIRef(u'http://www.rdflib.net/terms/says')
303-
imtheone = Literal(u'I\'m the one', lang='en')
303+
objects = [
304+
Literal(u'I\'m the one', lang='en'),
305+
Literal(u'こんにちは', lang='ja'),
306+
Literal(u'les garçons à Noël reçoivent des œufs', lang='fr')]
304307

305308
self.graph.parse(StringInputSource(xmltestdocXml), formal='xml')
306309

307310
objs = list(self.graph)
308311
self.assertEquals(len(objs), 3)
309-
o = objs[0]
310-
self.assertEquals(o, (bob, says, imtheone))
312+
for o in objs:
313+
self.assertEquals(o[0], bob)
314+
self.assertEquals(o[1], says)
315+
self.assertTrue(o[2] in objects)
311316

312317

313318
def testStoreLiteralsXmlQuote(self):

0 commit comments

Comments
 (0)