From 13724ce56f8d1ac8f6857162bab3606375898504 Mon Sep 17 00:00:00 2001 From: Jay Date: Mon, 24 Feb 2025 11:45:23 -0500 Subject: [PATCH] Started transforming tags into relationships. --- batch_import_threshold_tests.ods | Bin 0 -> 21846 bytes go.mod | 11 +++- go.sum | 110 ++++++++++++++++++++++++++++++- lib/graph.go | 33 ---------- lib/import.go | 79 +++++++++++++++++++--- lib/schema.go | 19 +++++- lib/write.go | 39 +++++++++++ 7 files changed, 244 insertions(+), 47 deletions(-) create mode 100644 batch_import_threshold_tests.ods create mode 100644 lib/write.go diff --git a/batch_import_threshold_tests.ods b/batch_import_threshold_tests.ods new file mode 100644 index 0000000000000000000000000000000000000000..0bae799f8b494eb87de5ba7b09ce0e8d5e6a5d44 GIT binary patch literal 21846 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 BK8pYV literal 0 HcmV?d00001 diff --git a/go.mod b/go.mod index 4d3dd88..35f0727 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,20 @@ module main go 1.23.5 require ( - github.com/nbd-wtf/go-nostr v0.49.7 + github.com/nbd-wtf/go-nostr v0.50.0 github.com/neo4j/neo4j-go-driver/v5 v5.27.0 ) require ( + github.com/btcsuite/btcd v0.24.2 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.5 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/coder/websocket v1.8.12 // indirect github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect + github.com/elnosh/gonuts v0.3.1-0.20250123162555-7c0381a585e3 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -22,5 +26,10 @@ require ( github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d // indirect + golang.org/x/sys v0.29.0 // indirect ) + +replace github.com/nbd-wtf/go-nostr => github.com/wisehodl/go-nostr v0.0.0-20250223095115-c98b2ea67e2a diff --git a/go.sum b/go.sum index 756a9e9..99141a4 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,71 @@ +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= +github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= +github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/elnosh/gonuts v0.3.1-0.20250123162555-7c0381a585e3 h1:k7evIqJ2BtFn191DgY/b03N2bMYA/iQwzr4f/uHYn20= +github.com/elnosh/gonuts v0.3.1-0.20250123162555-7c0381a585e3/go.mod h1:vgZomh4YQk7R3w4ltZc0sHwCmndfHkuX6V4sga/8oNs= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -23,18 +73,27 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/nbd-wtf/go-nostr v0.49.7 h1:4D9XCqjTJYqUPMuNJI27W5gaiklnTI12IzzWIAOFepE= -github.com/nbd-wtf/go-nostr v0.49.7/go.mod h1:M50QnhkraC5Ol93v3jqxSMm1aGxUQm5mlmkYw5DJzh8= github.com/neo4j/neo4j-go-driver/v5 v5.27.0 h1:YdsIxDjAQbjlP/4Ha9B/gF8Y39UdgdTwCyihSxy8qTw= github.com/neo4j/neo4j-go-driver/v5 v5.27.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -42,9 +101,56 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/wisehodl/go-nostr v0.0.0-20250223095115-c98b2ea67e2a h1:o1ZtdgzxJ5AZEOkPo83ASU8JvzhTe+IPWjJPUY+sMok= +github.com/wisehodl/go-nostr v0.0.0-20250223095115-c98b2ea67e2a/go.mod h1:M50QnhkraC5Ol93v3jqxSMm1aGxUQm5mlmkYw5DJzh8= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lib/graph.go b/lib/graph.go index bd1c6db..2644285 100644 --- a/lib/graph.go +++ b/lib/graph.go @@ -346,36 +346,3 @@ func DeserializeRelKey(sortKey string) (string, string, string) { rtype, startLabel, endLabel := parts[0], parts[1], parts[2] return rtype, startLabel, endLabel } - -// ======================================== -// Cypher Formatting Functions -// ======================================== - -// ToCypherLabel converts a node label or relationship type into its Cypher -// format. -func ToCypherLabel(label string) string { - return fmt.Sprintf(":`%s`", label) -} - -// ToCypherLabels converts a list of node labels into its Cypher format. -func ToCypherLabels(labels []string) string { - var cypherLabels []string - - for _, label := range labels { - cypherLabels = append(cypherLabels, ToCypherLabel(label)) - } - - return strings.Join(cypherLabels, "") -} - -func ToCypherProps(keys []string, prefix string) string { - if prefix == "" { - prefix = "$" - } - cypherPropsParts := []string{} - for _, key := range keys { - cypherPropsParts = append( - cypherPropsParts, fmt.Sprintf("%s: %s%s", key, prefix, key)) - } - return strings.Join(cypherPropsParts, ", ") -} diff --git a/lib/import.go b/lib/import.go index d7861ca..fbde95d 100644 --- a/lib/import.go +++ b/lib/import.go @@ -6,18 +6,19 @@ import ( "fmt" "log" "os" + "regexp" "strings" "sync" "github.com/nbd-wtf/go-nostr" + "github.com/nbd-wtf/go-nostr/nip60" "github.com/neo4j/neo4j-go-driver/v5/neo4j" ) // Workers func ImportEvents() { - - data, err := os.ReadFile("./export.json") + data, err := os.ReadFile("./zaps.json") if err != nil { panic(err) } @@ -35,7 +36,7 @@ func ImportEvents() { var event nostr.Event for i, line := range strings.Split(string(data), "\n") { - if i > 10000 { + if i > 2000000 { break } @@ -80,6 +81,12 @@ func ParseEvents(events chan nostr.Event) { eventNode.Props["kind"] = event.Kind eventNode.Props["content"] = event.Content + if event.Kind == nostr.KindZap { + // Event is a zap receipt + // Write the zap amount to the event + eventNode.Labels.Add("ZapReceiptEvent") + } + authorRel := NewSignedRel(userNode, eventNode, nil) subgraph.AddNode(userNode) @@ -91,13 +98,67 @@ func ParseEvents(events chan nostr.Event) { if len(tag) >= 2 { name := tag[0] value := tag[1] + var rest []string - // Special cases + if len(name)+len(value) > 8192 { + // Skip tags that are too large for the neo4j indexer + continue + } - tagNode := NewTagNode(name, value) - tagRel := NewTaggedRel(eventNode, tagNode, nil) - subgraph.AddNode(tagNode) - subgraph.AddRel(tagRel) + if len(tag) > 2 { + rest = append([]string{}, tag[2:]...) + } + + if event.Kind == nostr.KindZap && name == "bolt11" { + amount, err := nip60.GetSatoshisAmountFromBolt11(value) + if err == nil { + eventNode.Props["amount"] = amount + } else { + fmt.Println("Invalid bolt11 amount:", err) + } + } + + if name == "e" && + len(value) == 64 && + regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(value) { + // Tag is an event reference + // Create a relationship to the referenced event + referencedEventNode := NewEventNode(value) + referencesRel := NewReferencesEventRel( + eventNode, + referencedEventNode, + map[string]any{ + "name": name, + "value": value, + "rest": rest, + }) + subgraph.AddNode(referencedEventNode) + subgraph.AddRel(referencesRel) + + } else if name == "p" && + len(value) == 64 && + regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(value) { + // Tag is a user reference + // Create a relationship to the referenced user + referencedUserNode := NewUserNode(value) + referencesRel := NewReferencesUserRel( + eventNode, + referencedUserNode, + map[string]any{ + "name": name, + "value": value, + "rest": rest, + }) + subgraph.AddNode(referencedUserNode) + subgraph.AddRel(referencesRel) + + } else { + // Generic Tag + tagNode := NewTagNode(name, value, rest) + tagRel := NewTaggedRel(eventNode, tagNode, nil) + subgraph.AddNode(tagNode) + subgraph.AddRel(tagRel) + } } } @@ -308,7 +369,7 @@ func mergeRels( MATCH (start%s { %s }) MATCH (end%s { %s }) - CREATE (start)-[r%s]->(end) + MERGE (start)-[r%s]->(end) SET r += rel.props `, startCypherLabel, startCypherProps, diff --git a/lib/schema.go b/lib/schema.go index 93fd40a..fd6ddad 100644 --- a/lib/schema.go +++ b/lib/schema.go @@ -38,8 +38,11 @@ func NewEventNode(id string) *Node { return NewNode("Event", Properties{"id": id}) } -func NewTagNode(name string, value string) *Node { - return NewNode("Tag", Properties{"name": name, "value": value}) +func NewTagNode(name string, value string, rest []string) *Node { + return NewNode("Tag", Properties{ + "name": name, + "value": value, + "rest": rest}) } // ======================================== @@ -59,6 +62,18 @@ func NewTaggedRel( "TAGGED", "Event", "Tag", start, end, props) } +func NewReferencesEventRel( + start *Node, end *Node, props Properties) *Relationship { + return NewRelationshipWithValidation( + "REFERENCES", "Event", "Event", start, end, props) +} + +func NewReferencesUserRel( + start *Node, end *Node, props Properties) *Relationship { + return NewRelationshipWithValidation( + "REFERENCES", "Event", "User", start, end, props) +} + // ======================================== // Relationship Constructor Helpers // ======================================== diff --git a/lib/write.go b/lib/write.go new file mode 100644 index 0000000..7f331eb --- /dev/null +++ b/lib/write.go @@ -0,0 +1,39 @@ +package lib + +import ( + "fmt" + "strings" +) + +// ======================================== +// Cypher Formatting Functions +// ======================================== + +// ToCypherLabel converts a node label or relationship type into its Cypher +// format. +func ToCypherLabel(label string) string { + return fmt.Sprintf(":`%s`", label) +} + +// ToCypherLabels converts a list of node labels into its Cypher format. +func ToCypherLabels(labels []string) string { + var cypherLabels []string + + for _, label := range labels { + cypherLabels = append(cypherLabels, ToCypherLabel(label)) + } + + return strings.Join(cypherLabels, "") +} + +func ToCypherProps(keys []string, prefix string) string { + if prefix == "" { + prefix = "$" + } + cypherPropsParts := []string{} + for _, key := range keys { + cypherPropsParts = append( + cypherPropsParts, fmt.Sprintf("%s: %s%s", key, prefix, key)) + } + return strings.Join(cypherPropsParts, ", ") +}