File size: 2,755 Bytes
5a81b95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { EmailIngestor } from '../apps/backend/src/services/ingestors/EmailIngestor.js';
import { CalendarIngestor } from '../apps/backend/src/services/ingestors/CalendarIngestor.js';
import { neo4jAdapter } from '../apps/backend/src/adapters/Neo4jAdapter.js';
import { randomUUID } from 'crypto';
import fs from 'fs';
import path from 'path';

const loadEnvIfNeeded = () => {
  if (process.env.NEO4J_URI && process.env.NEO4J_USERNAME && process.env.NEO4J_PASSWORD) return;
  const envPath = path.join(process.cwd(), 'apps', 'backend', '.env');
  if (fs.existsSync(envPath)) {
    const lines = fs.readFileSync(envPath, 'utf-8').split(/\r?\n/);
    for (const line of lines) {
      const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
      if (m) {
        const [, k, v] = m;
        if (!process.env[k]) process.env[k] = v;
      }
    }
  }
};

const persistNodes = async (nodes) => {
  const persisted = [];
  for (const node of nodes) {
    const labels = (node.labels?.length ? node.labels : ['Private']).map((l) =>
      l.replace(/[^A-Za-z0-9_]/g, '')
    );
    const labelString = labels.map((l) => `:${l}`).join('');
    const props = { ...(node.properties || {}) };
    if (!props.externalId) props.externalId = randomUUID();
    if (node.ownerUid) {
      props.belongsTo = node.ownerUid;
      if (!labels.includes('Private')) labels.push('Private');
    }
    const cypher = `
      MERGE (n${labelString} {externalId: $props.externalId})
      SET n += $props
      WITH n, $ownerUid AS ownerUid
      OPTIONAL MATCH (u:User {uid: ownerUid})
      WITH n, ownerUid, u
      FOREACH (_ IN CASE WHEN ownerUid IS NULL THEN [] ELSE [1] END |
        MERGE (u:User {uid: ownerUid})
        ON CREATE SET u.name = 'Claus', u.role = 'Executive', u.access_level = 'god_mode'
        MERGE (n)-[:BELONGS_TO]->(u)
      )
      RETURN n.externalId AS externalId
    `;
    const res = await neo4jAdapter.executeQuery(cypher, { props, ownerUid: node.ownerUid ?? null });
    if (res && res[0]?.externalId) persisted.push(res[0].externalId);
  }
  return persisted;
};

const run = async () => {
  loadEnvIfNeeded();
  const ingest = async (ingestor) => {
    await ingestor.connect();
    const items = await ingestor.fetchRecent(2);
    const nodes = items.map((i) => ingestor.transformToGraphNode(i));
    return persistNodes(nodes);
  };

  await ingest(new EmailIngestor());
  await ingest(new CalendarIngestor());

  const res = await neo4jAdapter.executeQuery(
    'MATCH (u:User)-[r:BELONGS_TO]-(n:Private) RETURN u.uid AS uid, type(r) AS rel, labels(n) AS labels, coalesce(n.title, n.subject, n.bodyPreview) AS title LIMIT 5'
  );
  console.log(JSON.stringify(res, null, 2));
};

run().catch((err) => {
  console.error(err);
  process.exit(1);
});