How to make this not dangerous?

from neo4j import GraphDatabase

driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "pass"))

def add_friend(tx, name, friend_name):"MERGE (a:Person {name: $name}) "
           "MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
           name=name, friend_name=friend_name)

def print_friends(tx, name):
    for record in"MATCH (a:Person)-[:KNOWS]->(friend) WHERE = $name "
                         "RETURN ORDER BY", name=name):

def dictToProperties(properties_dict):
    props = ""
    for key in properties_dict:
        props += key
        props += ': '
        props += '\''
        props += properties_dict[key]
        props += '\''
        props += ', '
    return props[:-2]

def add_node(tx, labels, properties):"CREATE (" + ':'.join(labels) + " {" + dictToProperties(properties) + "}) ")

props = {'name': '\' }) \nWITH true as pass\nMATCH (e) DETACH DELETE e RETURN ({e: \''}

with driver.session() as session:
    session.write_transaction(add_friend, "Arthur", "Guinevere")
    session.write_transaction(add_friend, "Arthur", "Lancelot")
    session.write_transaction(add_friend, "Arthur", "Merlin")
    session.write_transaction(add_node, ['Person', 'Swedish'], props)
    session.read_transaction(print_friends, "Arthur") # (nothing to print)


The neo4j python driver provides this sort of "injection" protection, right ?
I wish it provided this kind of idiomatic function (add_node) that I'm trying to implement.

Hello Wis, welcome to the community. What do you mean by make this not dangerous? You're correct it's not possible to dynamically create nodes in the graph the way that you're trying to do, but that's probably for the best from a schema integrity point of view. In my experience it helps to know exactly what transactions are being run, etc.

Hi @MuddyBootsCode sorry for not being clear.
look at the value of name in the props dictionary, it causes what is commonly/popularly known as an "sql injection".
it's possible, but I agree with you it may not be good practice and that you need a schema model in code, preferably with an Object Graph Mapper (OGM).

for now I think I fixed it by making it return the records in the query and the method, like so:

def add_node(tx, labels, properties):
        "CREATE (p:"
        + ":".join(labels)
        + " {"
        + dictToProperties(properties)
        + "}) RETURN p"

now the parser returns this error with a python exception that I can catch:

neobolt.exceptions.CypherSyntaxError: RETURN can only be used at the end of the query (line 3, column 27 (offset: 83))

Ah, gotcha. Looks like you've got it figured out. Nice implementation.