ArcadeDB

Einführung in das Ruby-Interface zur NOSQL-Datenbank ArcadeDB.

Gemfile

gem 'arcadedb', git: "https://github.com/topofocus/arcadedb"
gem 'arcade-time-graph', git: "https://github.com/topofocus/arcade-time-graph"

Skript

require 'arcade'
require 'arcade-time-graph'
ProjectRoot = Pathname.new( Dir.pwd ).parent # Location der Config-Datei
Arcade::Init.connect 
# Referenz zur Datenbank
db =  Arcade::Init.db 
# test
puts db.hierarchy type: :vertex

Config-Datei

---
:environment:
  :test:
    dbname: playground
    user:  root
    pass:  ***
  :development:
    dbname: hierondev
    user: root
    pass:  ***
  :production:
    dbname: hieronymus
    user: root
    pass: ***
:admin:
  :host: 10.247.8.109
  :port: 2480
  :user: root
  :pass: ***
:logger: stdout           # 'file' or 'stdout'
:namespace: Arcade        # Default Namespace
:autoload: true           # load model if a link is detected in a record

ArcadeDB ist eine universale NoSQL-Datenbank. »NoSQL« steht für »Not Only SQL«. Die Datenbank ist eine Alternative zu klassischen rationalen Datenbanken.

Die Daten sind entweder als Graphen angelegt, werden über Schlüssel abgespeichert (Key/Value) oder sind lose strukturierte Dokumente. Die Datenbank verwendet Standardprotokolle für die Datenzugriffe.

Modelfiles

Die Datenbank ist hoch flexibel und kann weitgehend mit adhoc-Daten gefüllt werden. Ruby-Model-Objektklassen und die korrespondierenden Datenbank-Types müssen trotzdem definiert werden. Die Datenbank kann auch strikt definiert werden, wie es bei RDMS-Datenbanken erforderlich ist.

Hier ein Beispiel für die Definition einer Person

 module Arcade
  class Person
    attribute :name,        Types::Nominal::String
    attribute :surname,     Types::Nominal::String.default( "".freeze  )
    attribute :email?,      Types::Email
    attribute :age?,        Types::Nominal::Integer
    attribute :active,      Types::Nominal::Bool.default( true  )
    attribute :conterfeil?, Types::Nominal::Any

    def self.db_init
       File.read(__FILE__).gsub(/.*__END__/m, '')
    end
  end
 end
 ## The code below is executed on the database after the database-type is created
 ## Use the output of `ModelClass.database_name` as DB type  name
 ##
 __END__
 CREATE PROPERTY user.name STRING
 CREATE PROPERTY user.surname STRING
 CREATE PROPERTY user.email STRING
 CREATE INDEX  ON user ( name  ) NOTUNIQUE
 CREATE INDEX  ON user ( name, surname, email  ) UNIQUE

Die Definitionen sind weitgehend selbsterklärend. Attribute mit einem Fragezeichen sind optional. Die Daten sind streng typisiert, das ist Voraussetzung für einen konsistenten Datenbankaufbau.

Die Datenbankdefinition wird beim Programmstart eingelesen. Person.create_type überträgt die Definition von Attributen (Properties) und Indizes an zur Datenbank.

Adhoc Datenbank

Zusätzlich zu den definierten Datenbankfeldern können weitere, untypisierte Felder angelegt werden.

So können dynamisch unidirektionale Abhängigkeiten adhoc dargestellt werden:

Person.create name: 'Hugo', surname: 'Gans'
            father: Person.create( name: 'Otto', surname: 'Gans' ),                        
          children: [ "Eva", "Ulli", "Uwe", "Georg" ].map do |c| 
                    Person.create name: c, surname: 'Gans'    
                                                     end
                                     

Diese Anweisung legt father und children-Felder an und füllt sie mit Personen. Die Ausgabe des Datensatzes zeigt die angelegten Personen in Form ihrer Datenbank-Identitäten.

puts hugo.to_human
<person[#187:0]:  active: true, 
                children: ["#175:0", "#178:0", "#181:0", "#184:0"], 
                  father: <person[#172:0]: active : true, name : Otto, surname : Gans>, 
                    name: Hugo, surname: Gans> 

puts hugo.children.map &:expand
<person[#175:0]: active : true, name : Eva, surname : Gans> 
<person[#178:0]: active : true, name : Ulli, surname : Gans>
<person[#181:0]: active : true, name : Uwe, surname : Gans>
<person[#184:0]: active : true, name : Georg, surname : Gans>