Skip to content

Counter-proposal discussion: more Ruby-like #2

Open
@leehericks

Description

@leehericks

An official, core driver near to the Neo4j driver specification sounds great, but the proposal doesn't feel Ruby-like. I also think Rails developers will prefer the abstraction built over the driver (neo4j.rb)

Here is an in-discussion revision to the proposal which keeps all the structure of the driver specification while utilizing what makes Ruby great.

# Java loves factory and builder patterns, ok. Creating the driver:
include Neo4j::Driver
driver = GraphDatabase.driver('bolt://localhost:7687', 
                              AuthTokens.basic('neo4j', 'password'),
                              ...config)

# Ruby is flexible so we can give some different ways to use this.
# First, Neo4j docs say sessions are lightweight, disposable, and usually scoped in a 
# context block when the language supports it, so let's do that. 
# Ruby blocks and instance_eval (with proper care for delegating method calls
# back to the original context via `method_missing`) give us clean DSL with automatically
# closing the session. 

# Default session-level access mode is :write
driver.session do
  run('MATCH (a:Person) RETURN a.name AS name').to_a
end

# Session-level access mode with auto-commit transaction
driver.session :read do
  run('MATCH (a:Person) RETURN a.name AS name').to_a
end

# Transaction-level access mode (multiple transactions per session)
driver.session do
  transaction :read do
    run('MATCH (a:Person) RETURN a.name AS name').to_a 
  end
end

# Note that while the blocks are executed in the scope of the session or transaction,
# the objects can be explicitly used through parameters:
driver.session do |session|
  session.transaction { |tx| create_person_node(tx, "Lee") }
end

def create_person_node(tx, name)
  tx.run 'CREATE (a:Person {name: $name})', name: name
end

# Further, using a method symbol and variable arguments can create a clean, readable solution.
# Default write access mode
driver.session do
  transaction :create_person_node, "Lee"
end

# Bookmarks are sent from the server after each transaction is commit.
# transaction is called on the session object, meaning we can make the last available.
bookmarks = []

driver.session do
  transaction :write { run ... }
  bookmarks << last_bookmark
end

# OR

bookmarks << driver.session do
  transaction :write { run ... }
  transaction :write { run ... }
  transaction :write { run ... }
  last_bookmark
end

# Then let's use them for a next session
driver.session :read, bookmarks do
  run('MATCH (a:Person) RETURN a.name AS name').to_a
end

# So, if I may rewrite the last method in the 3.4 example, line 223:
def add_employ_and_make_friends
  bookmarks = []

  driver.session do
    transaction :add_company, "Wayne Enterprises"
    transaction :add_person "Alice"
    transaction :employ, "Alice", "Wayne Enterprises"
    bookmarks << last_bookmark
  end

  driver.session do
    transaction :add_company, "LexCorp"
    transaction :add_person, "Bob"
    transaction :employ, "Bob", "LexCorp"
    bookmarks << last_bookmark
  end

  driver.session bookmarks do
    transaction :make_friends, "Alice", "Bob"
    transaction :read, :print_friends
  end
end

driver.close

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions