Example #1
0
    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