module Arcade module Api extend Primitives =begin This is a simple admin interface $ Arcade::Api.databases # returns an Array of known databases $ Arcade::Api.create_database # returns true if succesfull $ Arcade::Api.drop_database # returns true if successfull $ Arcade::Api.create_document , , attributes $ Arcade::Api.execute( [, session_id: some_session_id ]) { } $ Arcade::Api.query( ) { } $ Arcade::Api.get_record , rid # returns a hash is either a string or a hash { :query => " ", :language => one of :sql, :cypher, :gmelion: :neo4j , :params => a hash of parameters, :limit => a number , :serializer: one of :graph, :record } =end # ------------------------------ Service methods ------------------------------------------------- # # ------------------------------ ------------------------------------------------- # # ------------------------------ databases ------------------------------------------------- # # returns an array of databases present on the database-server # def self.databases get_data 'databases' end # ------------------------------ create database ------------------------------------------------- # # creates a database if not present # def self.create_database name return if databases.include?( name.to_s ) payload = { "command" => "create database #{name}" } post_data "server", payload rescue Arcade::QueryError => e logger.fatal "Create database #{name} through \"POST create/#{name}\" failed" logger.fatal e raise end # ------------------------------ drop database ------------------------------------------------- # # deletes the given database # def self.drop_database name return unless databases.include?( name.to_s ) payload = {"command" => "drop database #{name}" } post_data "server", payload rescue Arcade::QueryError => e logger.fatal "Drop database #{name} through \"POST drop database/#{name}\" failed" raise end # ------------------------------ create document ------------------------------------------------- # # adds a document to the specified database table # # specify database-fields as hash-type parameters # # i.e Arcade::Api.create_document 'devel', 'documents', name: 'herta meyer', age: 56, sex: 'f' # # returns the rid of the inserted dataset # def self.create_document database, type, session_id: nil, **attributes payload = { "@type" => type }.merge( attributes ) if session_id.nil? post_data "document/#{database}", payload else post_transaction "document/#{database}", payload, session_id: session_id end end # ------------------------------ execute ------------------------------------------------- # # executes a sql-query in the specified database # # the query is provided as block # # returns an Array of results (if propriate) # i.e # Arcade::Api.execute( "devel" ) { 'select from test ' } # =y [{"@rid"=>"#57:0", "@type"=>"test", "name"=>"Hugo"}, {"@rid"=>"#60:0", "@type"=>"test", "name"=>"Hubert"}] # def self.execute database, session_id: nil pl = provide_payload(yield) if session_id.nil? post_data "command/#{database}" , pl else post_transaction "command/#{database}" , pl, session_id: session_id end end # ------------------------------ query ------------------------------------------------- # # same for idempotent queries def self.query database, query, session_id: nil if session_id.nil? post_data "query/#{database}" , provide_payload(query) else post_transaction "query/#{database}" , provide_payload(query), session_id: session_id end end # ------------------------------ get_record ------------------------------------------------- # # fetches a record by providing database and rid # and returns the result as hash # # > Api.get_record 'devel', '225:6' # > Api.get_record 'devel', 225, 6 # > Api.get_record 'devel', '#225:6' # => {:@out=>0, :@rid=>"#225:6", :@in=>0, :@type=>"my_names", :name=>"Zaber", :@cat=>"v"} def self.get_record database, *rid rid = rid.join(':') rid = rid[1..-1] if rid[0]=="#" if rid.rid? get_data "document/#{database}/#{rid}" else raise Error "Get requires a rid input" end end # ------------------------------ property ------------------------------------------------- # # Adds properties to the type # # call via # Api.property , , name1: a_format , name2: a_format # # Format is one of # Boolean, Integer, Short, Long, Float, Double, String # Datetime, Binary, Byte, Decimal, Link # Embedded, EmbeddedList, EmbeddedMap # # In case of an Error, anything is rolled back and nil is returned # def self.property database, type, **args s= begin_transaction database success = args.map do | name, format | r= execute(database, session_id: s) {" create property #{type.to_s}.#{name.to_s} #{format.to_s} " } &.first r.nil? ? false : r[:operation] == 'create property' end.uniq if success == [true] commit database, session_id: s true else rollback database log: false, session_id: s false end end # ------------------------------ index ------------------------------------------------- # def self.index database, type, name , *properties properties = properties.map( &:to_s ) unique_requested = "unique" if properties.delete("unique") unique_requested = "notunique" if properties.delete("notunique" ) automatic = true if properties << name if properties.empty? success = execute(database) {" create index IF NOT EXISTS on #{type} (#{properties.join(', ')}) #{unique_requested}" } &.first # puts "success: #{success}" success[:operation] == 'create index' end private def self.logger Database.logger end def self. provide_payload( the_yield, action: :post ) unless the_yield.is_a? Hash logger.info "Q: #{the_yield}" the_yield = { :query => the_yield } end { language: 'sql' }.merge( the_yield.map do | key, value | case key when :query action == :post ? [ :command, value ] : [ :query, value ] when :limit [ :limit , value ] when :params if value.is_a? Hash [ :params, value ] end # serializer (optional) specify the serializer used for the result: # graph: returns as a graph separating vertices from edges # record: returns everything as records # by default it’s like record but with additional metadata for vertex records, # such as the number of outgoing edges in @out property and total incoming edges # in @in property. This serialzier is used by Studio when :serializer if [:graph, :record].include? value.to_sym [ :serializer, value.to_sym ] end when :language if [:sql, :cypher, :gremlin, :neo4j, :sqlscript, :graphql, :mongo ].include? value.to_sym [ :language, value.to_sym ] end end # case end .to_h ) # map end def self.auth @a ||= { httpauth: :basic, username: Config.admin[:user], password: Config.admin[:pass] } end end end