def updateAll(self, update, replace, removedResources=None): ''' Add, remove, update, or replace resources in the store. `update`: A list of either statements or pjson conforming dicts that will be processed with the same semantics as the `update` method. `replace`: A list of either statements or pjson conforming dicts that will be processed with the same semantics as the `replace` method. `removedResources`: A list of ids of resources that will be removed from the store. ''' if not self.join(self.requestProcessor.txnSvc): #not in a transaction, so call this inside one func = lambda: self.updateAll(update, replace, removedResources) return self.requestProcessor.executeTransaction(func) newStatements = [] newListResources = set() removedResources = set(removedResources or []) removals = [] skipListValues = [] #update: #replace stmts with matching subject and property #if the old value is a list, remove the entire list #XXX handle scope: if a non-empty scope is specified, only compare updateStmts, ujsonrep, emptyobjs = self._toStatements(update) root = OrderedModel(updateStmts, self._isEmbedded) currentListResource = None for (resource, prop, values) in root.groupbyProp(): #note: for list resources, rdf:type will be sorted first #but don't assume they are present if currentListResource == resource: continue if (prop == base.RDF_MS_BASE+'type' and (pjson.PROPSEQTYPE, base.OBJECT_TYPE_RESOURCE) in values): currentListResource = resource newListResources.add(resource) continue if prop in (base.RDF_SCHEMA_BASE+u'member', base.RDF_SCHEMA_BASE+u'first'): #if list just replace the entire list removedResources.add(resource) currentListResource = resource newListResources.add(resource) continue currentStmts = self.model.getStatements(resource, prop) if currentStmts: currentValues = [(s.object, s.objectType) for s in currentStmts] for currentStmt in currentStmts: currentObject, currentObjectType = currentStmt[2:4] found = None if (currentObject, currentObjectType) in values: found = currentObject, currentObjectType else: if (self._isEmbedded(currentObject,currentObjectType) and currentObject not in root.subjectDict): #instead of replacing stmts, rename new embedded #resource to old name (but only if new name doesn't #match another existing name and old name isn't used) embeddedvalues = [v[0] for v in values if self._isEmbedded(*v) and v not in currentValues] if embeddedvalues: #not optimal, but for now just take the first one embeddedvalue = embeddedvalues.pop(0) found = embeddedvalue, currentObjectType #give the new bnode the same name as the old one #note: bnode subjects are sorted last so modifying #those statement now is ok root.renameResource(embeddedvalue, currentObject) if found: values.remove(found) listuri = self._getPropListName(resource, prop) skipListValues.append( (listuri, found) ) else: #new statement replaces current statement removals.append(currentStmt) self._removePropLists( (currentStmt,) ) for value, valueType in values: newStatements.append( base.Statement(resource,prop, value, valueType) ) for listRes in newListResources: for liststmt in root.subjectDict[listRes]: if (liststmt[0], liststmt[2:4]) not in skipListValues: newStatements.append( liststmt ) #replace: #replace all properties of the given resources replaceStmts, replaceJson, emptyobjs = self._toStatements(replace) if emptyobjs: removedResources.update(emptyobjs) #get all statements with the subject and remove them (along with associated lists) root = OrderedModel(replaceStmts, self._isEmbedded) renamed = {} for resource in root.resources: currentStmts = self.model.getStatements(resource) newStmts = root.getProperties(resource) currentEmbedded = None for stmt in currentStmts: matchStmt = None if stmt not in newStmts: if (self._isEmbedded(stmt.object,stmt.objectType) and stmt.object not in root.subjectDict): #see if we can just rename an new embedded object #instead of replacing this stmt for newstmt in newStmts: if newstmt[1] == stmt[1] and self._isEmbedded(newstmt[2],newstmt[3]): if currentEmbedded is None: currentEmbedded = [s.object for s in currentStmts if self._isEmbedded(s.object, s.objectType)] #only replace if the new name isn't an existing name if newstmt.object not in currentEmbedded and newstmt.object not in renamed: matchStmt = newstmt listuri = self._getPropListName(newstmt[0], newstmt[1]) root.renameResource(newstmt.object, stmt.object, listuri) renamed[newstmt.object] = stmt.object newStmts = root.getProperties(resource) break else: matchStmt = stmt if matchStmt: root.removeStatement(matchStmt) else: removals.append(stmt) #the new proplist probably have different ids even for values that #don't need to be added so remove all current proplists self._removePropLists(currentStmts) newStatements.extend( root.getAll() ) #remove: remove all statements and associated lists removals.extend( self._getStatementsForResources(removedResources) ) embeddedAdded = set() for stmt in newStatements: if self._isEmbedded(stmt.object, stmt.objectType): embeddedAdded.add(stmt.object) removals.extend(self._removeEmbedded(removals, embeddedAdded)) self._remove(removals) addStmts = self.add(newStatements) return addStmts, removals