Spaces:
Paused
Paused
| 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); | |
| }); | |