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«. Sie kann also mehr als Sql-Datenbankabfragen

Die Daten können als Graphen organisiert werden. Die Daten sind in Vertices gespeichert, die über Edges verbunden sind. Alternativ werden sie über Schlüssel abgespeichert (Key/Value). Zuletzt können die Daten in lose strukturierten Dokumenten organisiert werden. Alle denkbaren Hybridlösungen werden natürlich unterstützt. Die Datenbank verwendet Standardprotokolle für die Datenzugriffe.

Modelfiles

In einem model-Verzeichnis wird (analog zu Rails) Ruby-seitig die Datenstruktur definiert. In den Model-Files werden Ruby-Model-Objektklassen und die korrespondierenden Datenbank-Types definiert. Falls erforderlich können Datenbank-Objekte strikt definiert werden. Wenn Indizes definiert werden, ist eine strikte Definition der Datenbank nötig.

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 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>