A pure-MoonBit Neo4j client: Bolt protocol, PackStream codec, HTTP transactional endpoint, and a typed Cypher query builder.
moon add Rz-coder8848/moon-neo4jimport { "Rz-coder8848/moon-neo4j" @lib }| Layer | What it does | Entry points |
|---|---|---|
| PackStream codec | value model + binary encoder/decoder | PackStreamValue, packstream_encode, packstream_decode |
| Bolt transport | byte pipe abstraction + in-memory mock | Transport, MockTransport |
| Bolt handshake | magic 0x6060B017 + version negotiation | bolt_version, handshake_message, parse_handshake_response |
| Bolt messages | message signatures, builders, parser, chunked framing | hello, run, begin, commit, rollback, pull, frame, unframe, parse_message |
| Session | connection state machine | BoltConnection, ConnState |
| Transactions | explicit BEGIN / COMMIT / ROLLBACK | Transaction |
| Cypher builder | typed, injection-safe query construction | Query |
| HTTP endpoint | /db/{database}/tx request/response codec | build_tx_request, parse_tx_response, tx_commit, value_to_json, value_from_json |
| Demo | runnable Matrix movie-graph demo | demo_actors, demo_add_person |
let q = @lib.Query::new()
let title = q.param(PackStreamValue::str("The Matrix"))
q.match_("(p:Person)-[:ACTED_IN]->(m:Movie)")
q.where_("m.title = " + title)
q.return_("p.name")
q.order_by("p.name")
let (cypher, params) = q.build()
// cypher == "MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WHERE m.title = $p0 RETURN p.name ORDER BY p.name"
// params == [("p0", PackStreamValue::str("The Matrix"))]let conn = BoltConnection::new(transport) // transport : Transport
let _ = conn.handshake([bolt_version(5, 1, 0)])
let _ = conn.authenticate([("user_agent", PackStreamValue::str("my-app/1.0"))])
let (cypher, params) = q.build()
match conn.run_query(cypher, params) {
Some(rows) => println("rows: \{rows.length()}")
None => println("query failed")
}let tx = Transaction::new(conn)
if tx.begin() {
let _ = tx.run("CREATE (n:Person {name: \$p0})", [("p0", PackStreamValue::str("Lana"))])
let _ = tx.commit()
}let resp = tx_commit(
client, // client : HttpClient
"http://localhost:7474/db/neo4j/tx/commit",
[Statement::new("RETURN 1", [])],
)moon run cmd/main # query actors of "The Matrix", then add a person in a transaction
moon run cmd/main add Lana # run only the "add a person" demomoon check # type-checks clean
moon test # 83 whitebox + blackbox tests
moon fmt # formats the code.
├── packstream.mbt # PackStream value model + codec
├── stream.mbt # streaming reader/writer
├── message.mbt # Bolt message codec + chunked framing
├── handshake.mbt # Bolt handshake (magic + version negotiation)
├── transport.mbt # Transport trait + MockTransport
├── session.mbt # BoltConnection state machine
├── transaction.mbt # explicit transactions
├── cypher.mbt # typed Cypher query builder
├── http.mbt # HTTP transactional endpoint codec
├── demo.mbt # Matrix movie-graph demo
├── cmd/main/ # demo CLI (executable package)
└── moon.mod / moon.pkgpub trait Transport {
fn write(Self, Bytes) -> Unit
fn read_exact(Self, Int) -> Bytes?
fn close(Self) -> Unit
}fn[T : Transport] BoltConnection::authenticate(self : BoltConnection[T], metadata : Array[(String, PackStreamValue)]) -> ServerMessage?fn[T : Transport] BoltConnection::begin_tx(self : BoltConnection[T], extra : Array[(String, PackStreamValue)]) -> ServerMessage?fn[T : Transport] BoltConnection::handshake(self : BoltConnection[T], versions : Array[Int]) -> Int?fn[T : Transport] BoltConnection::pull_next(self : BoltConnection[T], extra : Array[(String, PackStreamValue)]) -> ServerMessage?fn[T : Transport] BoltConnection::run_query(self : BoltConnection[T], query : String, parameters : Array[(String, PackStreamValue)]) -> Array[Array[PackStreamValue]]?fn[T : Transport] BoltConnection::start_run(self : BoltConnection[T], query : String, parameters : Array[(String, PackStreamValue)], extra : Array[(String, PackStreamValue)]) -> ServerMessage?impl HttpClient for MockHttpClientimpl Transport for MockTransportpub enum PackStreamValue {
Null
Bool(Bool)
Int(Int64)
Float(Double)
Str(String)
List(Array[PackStreamValue])
Map(Array[(String, PackStreamValue)])
Struct(Int, Array[PackStreamValue])
Bytes(Bytes)
} derive(Eq, Debug)impl Show for PackStreamValuepub struct Reader {
bytes : Bytes
pos : Int
}pub enum ServerMessage {
Success(Array[(String, PackStreamValue)])
Record(Array[PackStreamValue])
Failure(Array[(String, PackStreamValue)])
Ignored
} derive(Eq, Debug)pub struct Statement {
statement : String
parameters : Array[(String, PackStreamValue)]
} derive(Eq, Debug)fn[T : Transport] Transaction::run(self : Transaction[T], query : String, parameters : Array[(String, PackStreamValue)]) -> Array[Array[PackStreamValue]]?fn bolt_version(major : Int, minor : Int, range : Int) -> Intfn demo_actors(title : String) -> Unitfn demo_add_person(name : String, born : Int64) -> Unitfn parse_handshake_response(bytes : Bytes) -> Int?fn run(query : String, parameters : Array[(String, PackStreamValue)], extra : Array[(String, PackStreamValue)]) -> PackStreamValuefn[T : HttpClient] tx_commit(client : T, url : String, statements : Array[Statement]) -> TxResponse?fn unframe(bytes : Bytes) -> Bytes?Install
Download zipA pure-MoonBit Neo4j client: Bolt protocol, PackStream codec, HTTP transactional endpoint, and a typed Cypher query builder.