Add one relationship to the extent

        origin - origin of the relationship (similar to an RDF subject)
        rel - type IRI of the relationship (similar to an RDF predicate)
        target - target of the relationship (similar to an RDF object), a boolean, floating point or unicode object
        attrs - optional attribute mapping of relationship metadata, i.e. {attrname1: attrval1, attrname2: attrval2}
        rid - optional ID for the relationship in IRI form. If not specified one will be generated.

def add(self, origin, rel, target, attrs=None, rid=None):
        '''
        Add one relationship to the extent

        origin - origin of the relationship (similar to an RDF subject)
        rel - type IRI of the relationship (similar to an RDF predicate)
        target - target of the relationship (similar to an RDF object), a boolean, floating point or unicode object
        attrs - optional attribute mapping of relationship metadata, i.e. {attrname1: attrval1, attrname2: attrval2}
        rid - optional ID for the relationship in IRI form. If not specified one will be generated.

        '''
        #FIXME no it doesn't re:
        #returns an ID (IRI) for the resulting relationship
        cur = self._conn.cursor()
        #relationship.
        if rid:
            querystr = "INSERT INTO relationship (origin, rel, target, rid) VALUES (%s, %s, %s, %s) RETURNING rawid;"
            cur.execute(querystr, (origin, rel, target, rid))
        else:
            querystr = "INSERT INTO relationship (origin, rel, target) VALUES (%s, %s, %s) RETURNING rawid;"
            cur.execute(querystr, (origin, rel, target))
        rawid = cur.fetchone()[0]
        for a_name, a_val in attrs.items():
            querystr = "INSERT INTO attribute (rawid, name, value) VALUES (%s, %s, %s);"
            cur.execute(querystr, (rawid, a_name, a_val))
        self._conn.commit()
        cur.close()
        return