Created
July 6, 2013 09:47
-
-
Save andreasronge/5939419 to your computer and use it in GitHub Desktop.
Spike on neo4j 2.0 featrues
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'java' | |
require 'forwardable' | |
require 'fileutils' | |
# Load Neo4j Jars for the jars folder | |
# Put the neo4j 2.0 jars there | |
jar_folder = File.expand_path('../jars', __FILE__) | |
jars = Dir.new(jar_folder).entries.find_all { |x| x =~ /\.jar$/ } | |
jars.each { |jar| require File.expand_path(jar, jar_folder) } | |
# See end of this file for example of usage | |
module Neo4j | |
class Transaction | |
def self.new(instance = Database.instance) | |
instance.begin_tx | |
end | |
def self.run(run_in_tx=true) | |
raise ArgumentError.new("Expected a block to run in Transaction.run") unless block_given? | |
return yield(nil) unless run_in_tx | |
begin | |
tx = Neo4j::Transaction.new | |
ret = yield tx | |
tx.success | |
rescue Exception => e | |
if e.respond_to?(:cause) && e.cause | |
puts "Java Exception in a transaction, cause: #{e.cause}" | |
e.cause.print_stack_trace | |
end | |
tx.failure unless tx.nil? | |
raise | |
ensure | |
tx.finish unless tx.nil? | |
end | |
ret | |
end | |
end | |
module TxMethods | |
def tx_methods(*methods) | |
methods.each do |method| | |
tx_method = "#{method}_in_tx" | |
send(:alias_method, tx_method, method) | |
send(:define_method, method) do |*args| | |
Transaction.run(Database.instance.auto_commit?) { send(tx_method, *args) } | |
end | |
end | |
end | |
end | |
# wrapps Neo4j ResourceIterator, automatically close it | |
class ResourceIterator | |
include Enumerable | |
def initialize(iterable) | |
@_iterable = iterable | |
end | |
def each | |
iterator = @_iterable.iterator | |
while (iterator.has_next) | |
yield iterator.next | |
end | |
ensure | |
iterator.close | |
end | |
end | |
class Label | |
extend TxMethods | |
attr_reader :name | |
JAVA_CLASS = Java::OrgNeo4jGraphdb::DynamicLabel | |
def initialize(name) | |
@name = name.to_s | |
end | |
def to_s | |
@name | |
end | |
def find_nodes(key, value, db = Database.instance) | |
ResourceIterator.new db.find_nodes_by_label_and_property(to_java, key, value) | |
end | |
def to_java | |
self.class.to_java(@name) | |
end | |
def index(*properties) | |
db = properties.last.kind_of?(Database) ? properties.pop : Database.instance | |
index_creator = db.schema.index_for(to_java) | |
# we can also use the PropertyConstraintCreator here | |
properties.inject(index_creator) {|creator, key| creator.on(key.to_s)}.create | |
end | |
tx_methods :index | |
class << self | |
def to_java(labels) | |
if labels.is_a?(Array) | |
labels.inject([]) { |result, label| result << JAVA_CLASS.label(label.to_s) }.to_java(JAVA_CLASS) | |
else | |
JAVA_CLASS.label(labels.to_s) | |
end | |
end | |
end | |
end | |
module Properties | |
extend TxMethods | |
def []=(key,value) | |
set_property(key.to_s, value) | |
end | |
tx_methods :[]= | |
def [](key) | |
get_property(key.to_s) | |
end | |
end | |
module Labels | |
def labels | |
get_labels.map{|x| Label.new(x.name) } | |
end | |
end | |
class Node | |
# include these modules only for documentation purpose | |
extend TxMethods | |
include Properties | |
include Labels | |
class << self | |
extend TxMethods | |
# Returns a new neo4j Node. | |
# The return node is actually an Java object of type Java::OrgNeo4jGraphdb::Node java object | |
# which has been extended (see the included mixins for Neo4j::Node). | |
def new(properties = {}, *labels_or_db) | |
db = labels_or_db.last.kind_of?(Database) ? labels_or_db.pop : Database.instance | |
_java_node = db.create_node(Label.to_java(labels_or_db)) | |
properties.each_pair {|k,v| _java_node.set_property(k,v)} | |
_java_node | |
end | |
tx_methods :new | |
# This method is used to extend a Java Neo4j class so that it includes the same mixins as this class. | |
def extend_java_class(java_clazz) | |
java_clazz.class_eval do | |
include Properties | |
include Labels | |
end | |
end | |
end | |
extend_java_class(Java::OrgNeo4jKernelImplCore::NodeProxy) | |
end | |
class Database | |
extend Forwardable | |
def_delegator :@graph_db, :schema | |
def_delegator :@graph_db, :begin_tx | |
def_delegator :@graph_db, :create_node | |
def_delegator :@graph_db, :findNodesByLabelAndProperty, :find_nodes_by_label_and_property | |
def initialize(path, config = {}) | |
factory = Java::OrgNeo4jGraphdbFactory::GraphDatabaseFactory.new | |
if (config[:delete_existing_db]) | |
FileUtils.rm_rf path | |
end | |
@graph_db = factory.newEmbeddedDatabase(path) | |
@auto_commit = !!config[:auto_commit] | |
@@instance ||= self | |
end | |
def auto_commit? | |
@auto_commit | |
end | |
def self.instance | |
@@instance | |
end | |
end | |
# Create a new database, which will wrap method with transactions | |
db = Database.new('hej', auto_commit: true, delete_existing_db: true) | |
# Create a new label with an index on property name | |
red = Label.new(:red) | |
red.index(:name) | |
# how should we specify constraints like unique ? | |
# red.index(:name).unique! | |
# red.index_unique(:name) | |
# red.index(:name, constraints: [:unique]) | |
# red.index do | |
# property :name, contraints: :unique | |
# end | |
# labels argument can be either, string, symbol or Label objects (anything responding to 'to_s') | |
node = Node.new({name: 'andreas'}, red, :green) | |
puts "Created node #{node[:name]} with labels #{node.labels.map(&:name).join(', ')}" | |
# Find nodes using the label | |
red.find_nodes(:name, "andreas").each do |node| | |
# notice that we do not wrap the java object, but instead extend the Java class with ruby methods | |
# prints out: FOUND andreas class Java::OrgNeo4jKernelImplCore::NodeProxy with labels red, green | |
puts "FOUND #{node[:name]} class #{node.class} with labels #{node.labels.map(&:name).join(', ')}" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment