"""
# Generate DB PR neo4j xml file.
- https://theorchard.atlassian.net/browse/PP-241
- https://github.com/theorchard/database/pull/16700
## Source Data Neo4J Queries
Used the following Neo4J queries to generate the input CSV files.
#### complicated_stress_test_user.csv
```cypher
MATCH(i:Identity {id: "f415420b-2227-4d9f-8676-a7bddcd74fc8"})--(p:Profile)--(l:Label)
RETURN
p.profileId as profile_id,
p.uuid as profile_uuid,
i.id as identity_uuid,
l.uuid as tenant_uuid,
l.id as vendor_id,
p.profileType as profile_type,
p.roles[0] as profile_role;
```
#### simple_stress_test_user.csv
```cypher
MATCH (v:Vendor)
WHERE v.uuid IN ['16bad0cd-489e-4e17-b75b-eef3b013fa6d']
RETURN
0 as profile_id,
v.uuid as profile_uuid,
v.uuid as tenant_uuid,
v.vendorId as vendor_id,
"LabelProfile" as profile_type,
"administrator" as profile_role;
```
#### integration_test_user.csv
```cypher
MATCH (v:Vendor)
WHERE v.uuid IN ['fff741c2-6def-4493-bfdf-c2bcb1128e02']
RETURN
0 as profile_id,
v.uuid as profile_uuid,
v.uuid as tenant_uuid,
v.vendorId as vendor_id,
"LabelProfile" as profile_type,
"administrator" as profile_role;
```
#### Validation Query
```cypher
// Should return 597 records
MATCH(i:Identity)--(p:Profile)--(l:Label)
WHERE
i.email in ["pdpteststresscomplicated@theorchard.com", "pdptest@theorchard.com", "pdpteststresssimple@theorchard.com"]
RETURN
p.profileId as profile_id,
i.email as email,
i.id as identity_uuid,
l.uuid as tenant_uuid,
l.id as vendor_id,
p.profileType as profile_type,
p.roles[0] as profile_role
ORDER BY profile_id;
// or just row counts
MATCH(i:Identity)--(p:Profile)--(l:Label)
WHERE
i.email in ["pdpteststresscomplicated@theorchard.com", "pdptest@theorchard.com", "pdpteststresssimple@theorchard.com"]
RETURN count(p);
```
> Rollback Cypher Queries
// Delete pdpteststresscomplicated Profile nodes and relationships and Identity
MATCH(i:Identity {email:'pdpteststresscomplicated@theorchard.com'})-[:HAS_PROFILE]->(p:Profile)
DETACH DELETE p;
MATCH(i:Identity {email:'pdpteststresscomplicated@theorchard.com'})
DETACH DELETE i;
//
MATCH(i:Identity {email:'pdptest@theorchard.com'})-[:HAS_PROFILE]->(p:Profile)
DETACH DELETE p;
MATCH(i:Identity {email:'pdptest@theorchard.com'})
DETACH DELETE i;
//
MATCH(i:Identity {email:'pdpteststresssimple@theorchard.com'})-[:HAS_PROFILE]->(p:Profile)
DETACH DELETE p;
MATCH(i:Identity {email:'pdpteststresssimple@theorchard.com'})
DETACH DELETE i;
"""
import codecs
import textwrap
from csv import DictReader
XML_HEADER = textwrap.dedent("""
""")
XML_FOOTER = textwrap.dedent("""
""")
def generate_qa_refresh_cypher(input_fn, output_fn, email, identity_uuid, identity_name, auth0_id,
start_profile_id, identityVarName, identity_num, output_fn_mode='w'):
"""
Generate the `11_pdp_stress_test_profiles.cypher` output file to
be included in https://github.com/theorchard/python-neo4j-cypher-scheduler
"""
# Create new profile ids and uuids per distinct tenant uuid
current_profile_id = start_profile_id
profile_to_vendor_lookup = set()
# 1st lines to crate the identity node.
lines = []
# read the input csv
with codecs.open(input_fn, 'r', 'utf-8-sig') as csvfile:
rdr = DictReader(csvfile)
p_count = 1
for i, row in enumerate(rdr):
# remove extra double-quotes
row = dict([(k, v.replace('"', "")) for k, v in row.items()])
tenant_uuid = row['tenant_uuid']
if tenant_uuid in profile_to_vendor_lookup:
# allow only 1 entry per label.uuid (tenant_uuid)
continue
# generate new profile uuid
profile_to_vendor_lookup.add(tenant_uuid)
current_profile_id += 1
p_node_name = f"p{identity_num}_{p_count}"
v_node_name = f"v{identity_num}_{p_count}"
ip_rel_name = f"ip_rel_{identityVarName}"
pv_rel_name = f"pv_rel_{p_node_name}"
p_count += 1
line = textwrap.dedent(f"""
MERGE ({identityVarName}:Identity {{email: '{email}'}})
ON CREATE SET
{identityVarName}.id = '{identity_uuid}',
{identityVarName}.name = '{identity_name}',
{identityVarName}.auth0UserId='{auth0_id}'
WITH {identityVarName}
MERGE (increment:IncrementId {{nodeName: 'Profile'}})
ON CREATE SET increment.id = 2
ON MATCH SET increment.id = increment.id + 1
CREATE ({p_node_name}:Profile {{
profileId: (increment.id-1),
profileType: 'FauxLabelProfile',
profileName: 'FauxLabelProfile_{p_node_name}',
roles: ['administrator'],
uuid: apoc.create.uuid()
}})
MERGE ({identityVarName})-[{ip_rel_name}:HAS_PROFILE]->({p_node_name})
WITH {identityVarName}, {p_node_name}
MATCH ({v_node_name}:Vendor{{id: {row['vendor_id']}}})
MERGE ({p_node_name})-[{pv_rel_name}:HAS_ACCESS_TO]->({v_node_name});""")
lines.append(line)
# lines.append(";\n\n")
print(f"Added {len(lines)} lines")
# write the file:
# output_fn_mode will create a new file (w) or append to an existing file (a)
with open(output_fn, output_fn_mode) as fp:
for line in lines:
fp.write(line + '\n')
print(f"wrote to {output_fn}")
return lines
def to_xml(lines, output_fn):
"""
Generate XML for
(p1_1)
WITH i1, p1_1
MATCH (v1_1:Vendor{id: 6971})
MERGE (p1_1)-[pv_rel_p1_1:HAS_ACCESS_TO]->(v1_1);
]]>
"""
change_num = 1
with open(output_fn, "w") as fp:
fp.write(XML_HEADER)
for change_num, line in enumerate(lines):
shifted_line = ""
slines = line.splitlines()
for j, e in enumerate(slines):
if not e.strip():
continue
if j < len(slines) - 1:
shifted_line += f"{16 * ' '}{e}\n"
else:
shifted_line += f"{16 * ' '}{e.replace(';', '')}"
changeset = f"""
"""
fp.write(changeset)
change_num += 1
fp.write(XML_FOOTER)
print(f"wrote to {output_fn}")
if __name__ == '__main__':
l1 = generate_qa_refresh_cypher(input_fn='./data/integration_test_user.csv',
output_fn="./data/11_pdp_stress_test_profiles.cypher",
email='pdptest@theorchard.com',
identity_uuid="4d5f24f5-83f9-4989-9f82-0924a5feaf88",
identity_name="Integration Test User",
auth0_id="6446c6827eadbdf56f275c32",
identityVarName="i1",
identity_num=1,
start_profile_id=36000)
l2 = generate_qa_refresh_cypher(input_fn='./data/simple_stress_test_user.csv',
output_fn="./data/11_pdp_stress_test_profiles.cypher",
email='pdpteststresssimple@theorchard.com',
identity_uuid="ef7cd70d-4314-49f9-b158-f3b3be66372f",
identity_name="Stress Test Simple User",
identityVarName="i2",
auth0_id="64808e1030bb6f683cf4dce8", start_profile_id=36001,
identity_num=2,
output_fn_mode="a"
)
l3 = generate_qa_refresh_cypher(input_fn='./data/complicated_stress_test_user.csv',
output_fn="./data/11_pdp_stress_test_profiles.cypher",
email='pdpteststresscomplicated@theorchard.com',
identity_uuid="5f0f10e0-9a9a-48e5-9616-a02886837e9",
identity_name="Stress Test Complicated User",
auth0_id="64808e48e65313dafa723db2",
identityVarName="i3",
output_fn_mode="a",
identity_num=3,
start_profile_id=36002)
output_lines = l1 + l2 + l3
to_xml(lines=output_lines,
output_fn="./data/PP-241-qa-pdptest-stress-test-user-jul18.xml")