require 'java' require 'fileutils' Dir["lib/jars/*"].each {|file| require file } class Geoff class Error < StandardError ; end class MissingIndexedProperty < Geoff::Error ; end class InvalidRules < Geoff::Error ; end def self.import *args Importer.import *args end class Importer Subgraph = org.neo4j.geoff.Subgraph class << self def import_files(*files, options) concatenated = files.map{|f|File.read f}.join "\n" import concatenated, options end def import_file(file, options = {}) rules = File.read(file) import(rules, options) end def import(geoff, options = {}) geoff = geoff.to_geoff unless geoff.is_a? String geoff = geoff.split "\n" if geoff.is_a? String new(geoff, options).go end end def initialize(rules, options) @rules = rules @options = options log @options.inspect end def go raise Geoff::InvalidRules.new('Invalid rules') unless validate_rules(@rules) delete_database if drop? log 'importing the database' import_geoff_rules @rules rebuild_indexes true end private def delete_database if testmode? Neo4j::Transaction.run do Neo4j.db.each_node do |n| n.del unless n.neo_id == 0 end end else Neo4j.db.shutdown FileUtils.rm_rf Neo4j::Config[:storage_path] log "restarting the database #{Neo4j::Config[:storage_path]}" Neo4j.db.start end end def import_geoff_rules(rules) sub_graph = Subgraph.new(rules) node_map = build_node_map org.neo4j.geoff.Geoff.mergeIntoNeo4j(sub_graph, Neo4j.db.graph, node_map ); end def build_node_map root_node.rels(:outgoing).inject({}) do |h, r| h[r.rel_type.to_s] = r.end_node h end.merge("ROOT" => root_node) end def rebuild_indexes log 're-building indexes' types = root_node.relationships.map { |r| Kernel.const_get(r.get_type.to_s) } Neo4j::Transaction.run do types.each do |type| re_index(type) end end end def re_index(type) log "-> re-indexing #{type}" props = type.instance_variable_get(:@_decl_props) indexed_props = props.find_all { |_, p| p.has_key?(:index) } indexed_props.each do |index| all = type.all all.each do |node| @current_node = node @current_index = index.first node.add_index index.first end end rescue NativeException => e log "-" * 80 message = "#{type} missing indexed attribute #{@current_index}, on node: #{@current_node.attributes}" log message log "-" * 80 log e.message log "-" * 80 raise Geoff::MissingIndexedProperty, message end def tx Neo4j::Transaction.run { yield if block_given? } end def root_node Neo4j.ref_node end def log(message) $stdout.puts message unless silent? end def drop? option_value?(:drop, false) end def silent? option_value? :silent end def testmode? option_value? :test end def option_value?(key, default = false) @options[key].nil? ? default : @options[key] end def validate_rules(rules) @invalid = Array(rules).map do |r| validate_rule(r) end.compact @invalid.each { |r, message| log "Rule '#{r}' is invalid: #{message}" } @invalid.empty? end def validate_rule(rule) Subgraph.new(Array(rule)) nil rescue Exception => e return [rule, e.message] end end end