Giter Club home page Giter Club logo

active-orient's Introduction

ActiveOrient

Use OrientDB to persistently store dynamic Ruby-Objects and use database queries to manage even very large datasets.

The Package ist tested with Ruby 2.2.1 and Orientdb 2.1.

To start you need a ruby 2.x Installation and a working OrientDB-Instance.
Install the Gem the usual way

For a quick start, go to the home directory of the package and start an irb-session

  require 'bundler/setup'
  require 'active-orient'

First, the Database-Server has to be specified. Then we can connect to a database. Assuming, the server is located on localhost, we just define »default-server«

   ActiveOrient::OrientDB.default_server= { user: 'your user', password: 'your password' }


  r = ActiveOrient::OrientDB.new  database: 'First'
   => I, [2015-08-18T09:49:18.858758 #88831]  INFO -- OrientDB#Connect: Connected to database First
   => #<ActiveOrient::OrientDB:0x000000048d0488 @res=#<RestClient::Resource:0x00000004927288 
       @url="http://localhost:2480", @block=nil, 
       @options={:user=>"xx", :password=>"***"}>, @database="First", @classes=[]> 

»r« is the Database-Instance itself. Obviously the database is empty.

Let's create some classes

   M = r.open_class          'classname'  # 
   M = r.create_class        'classname'  # creates or opens a basic document-class
   M = r.create_vertex_class 'classname'  # creates or opens a vertex-class 
   M = r.create_edge_class   'classname'  # creates or opens an edge-class, providing bidirectional links between documents

   r.delete_class   M                   # universal removal-of-the-class-method

»M« is the ActiveOrient::Model-Class itself, a constant pointing to the class-definition of the ruby-class. Its a shortcut for »ActiveOrient::Model::{Classname} and is reused if defined elsewhere.

If a schema is used, properties can be created and retrieved as well

 r.create_properties( M ) do
    {	symbol: { propertyType: 'STRING' },
   	con_id: { propertyType: 'INTEGER' },
      	details: { propertyType: 'LINK', linkedClass: 'Contracts' }
     }

 r.get_class_properties  M 

or

M.create_property  'symbol'
M.create_property  'con_id', type: 'integer'
M.create_property  'details', type: 'link', other_class: 'Contracts'

Active Model interface

Every OrientDB-Database-Class is mirrord as Ruby-Class. The Class itself is defined by

  M =  r.create_class 'classname' 
  M =  r.create_class { superclass_name:  'classname'  }
  Vertex =  r.create_vertex_class 'classname' 
  Edge   =  r.create_edge_class   'classname' 

and is of TYPE ActiveOrient::Model::{classname}

As for ActiveRecord-Tables, the Class itself provides methods to inspect and to filter datasets form the database.

  M.all   
  M.first
  M.last

returns an Array containing all Documents/Edges of the Class; the first and the last Record.

  M.where  town: 'Berlin'

performs a query on the class and returns the result as Array

  M.count where: { town: 'Berlin' }

gets the number of datasets fullfilling the search-criteria. Any parameter defining a valid SQL-Query in Orientdb can be provided to the count, where, first and last-method.

A »normal« Query is submitted via

  M.get_documents projection: { projection-parameter }
		  distinct: { some parameters }
		  where: { where-parameter }
		  order: { sorting-parameters }
		  group_by: { one grouping-parameter}
		  unwind:
		  skip:
		  limit:

#  or
 query = OrientSupport::OrientQuery.new {paramter}
 M.get_documents query: query

Basic graph-support:

  vertex_1 = Vertex.create  color: "blue"
  vertex_2 = Vertex.create  flower: "rose"
  Edge.create_edge attributes: { :birthday => Date.today }, from: vertex_1, to: vertex_2

connects the vertices and assigns the attributes to the edge

Links

A record in a database-class is defined by a »rid«. Every Model-Object comes with a handy »link«-method.

In OrientDB links are used to realise unidirectional 1:1 and 1:n relationships.

ActiveOrient autoloads Model-objects when they are accessed. As a consequence, if an Object is stored in Cluster 30 and id 2, then "#30:2" fully qualifies the ActiveOrient::Model object.

  TestLinks = r.create_class 'Test_link_class'
  TestBase = r.create_class 'Test_base_class'

  link_document =  TestLinks.create  att: 'one attribute' 
  base_document =  TestBase.create  base: 'my_base', single_link: link_document 

base_document.single_link just contains the rid. When accessed, the ActiveOrient::Model::Testlinkclass-object is autoloaded and

   base_document.single_link.att

reads the stored content of link_document.

To store a list of links to other Database-Objects a simple Array is allocated

  # predefined linkmap-properties
  base_document =  TestBase.create links: []
  ( 0 .. 20 ).each{ |y|  base_document.links << TestLinks.create  nr: y  }
  end
  #or in schemaless-mode
  base_document =  TestBase.create links: (0..20).map{|y|  TestLinks.create  nr: y  }

base_document.links behaves like a ruby-array.

If you got an undirectional graph

a --> b ---> c --> d

the graphelements can be explored by joining the objects ( a.b.c.d ), or (a.b[5].c[9].d )

Edges

Edges are easily handled

  Vertex = r.create_vertex_class 'd1'
  Eedge = r.create_edge_class   'e1'

  start =  Vertex.create  something: 'nice' 
  the_end   =  Vertex.create  something: 'not_nice' 
  the_edge = Edge.create_edge  attributes:  { transform_to: 'very bad' },
			       from: start,
			       to: the_end
 
  (...)
  the_edge.delete

There is a basic support for traversals throught a graph. The Edges are accessed by their names (downcase).

  start.e1[0]
  --> #<ActiveOrient::Model::E1:0x000000041e4e30 
	@metadata={"type"=>"d", "class"=>"E1", "version"=>60, "fieldTypes"=>"out=x,in=x", 
		   "cluster"=>16, "record"=>43}, 
        @attributes={"out"=>"#31:23", "in"=>"#31:15", "transform_to"=>"very bad" }>

The Attributes "in" and "out" can be used to move across the graph

   start.e1[0].out.something 
   ---> "not_nice
   start.e1[0].in.something 
   ---> "nice

Queries

Contrary to traditional SQL-based Databases OrientDB handles subqueries very efficient. In addition, OrientDB supports precompiled statements (let-Blocks).

ActiveOrient is equipped with a simple QueryGenerator: ActiveSupport::OrientQuery. It works in two modi: a comprehensive and a subsequent one

  
  q =  OrientSupport::OrientQuery.new
  q.from = Vertex     # If a constant is used, then the correspending
		      # ActiveOrient::Model-class is refered
  q.where << a: 2
  q.where << 'b > 3 '
  q.distinct = :profession
  q.order =  { :name => :asc }

is equivalent to

  q =  OrientSupport::OrientQuery.new from:  Vertex , 
				      where: [{ a: 2 }, 'b > 3 '],
				      distinct:  :profession,
				      order:  { :name => :asc }
  q.to_s
  => select distinct( profession ) from Vertex where a = 2 and b > 3  order by name asc

Both modes can be mixed.

If subqueries are nessesary, they can be introduced as OrientSupport::OrientQuery or as »let-block«.

  OQ = OrientSupport::OrientQuery
  q =  OQ.new from: 'ModelQuery'
  q.let << "$city = adress.city"
  q.where = "$city.country.name = 'Italy' OR $city.country.name = 'France'"
  q.to_s
  => select from ModelQuery let $city = adress.city where $city.country.name = 'Italy' OR $city.country.name = 'France' 

or

  q =  OQ.new
  q.let << { a:  OrientSupport::OrientQuery.new( from: '#5:0' ) }
  q.let << { b:  OrientSupport::OrientQuery.new( from: '#5:1' ) }
  q.let << '$c= UNIONALL($a,$b) '
  q.projection << 'expand( $c )'
  q.to_s
  => select expand( $c ) let $a = ( select from #5:0 ), $b = ( select from #5:1 ), $c= UNIONALL($a,$b)

or

  OpenInterest = r.open_class 'Openinterest'
  last_12_open_interest_records = OQ.new from: OpenInterest,  order: { fetch_date: :desc } , limit: 12
  bunch_of_contracts =  OQ.new from: last_12_open_interest_records, projection: 'expand( contracts )'
  distinct_contracts = OQ.new from: bunch_of_contracts, projection: 'expand( distinct(@rid) )'

  distinct_contracts.to_s
   => "select expand( distinct(@rid) ) from  ( select expand( contracts ) from  ( select  from Openinterest  order by fetch_date desc limit 12 )    )   " 
  
  cq = r.get_documents query: distinct_contracts

Execute SQL-Commands

Sql-commands can be executed as batch

The ActiveOrient::Query-Class provides a Query-Stack and an Records-Array which keeps the results. The ActiveOrient::Query-Class acts as Parent-Class for aggregated Records (without a @rid), which are ActiveOrient::Model::Myquery Objects. If a Query returns a database-record, the correct ActiveOrient::Model-Class is instantiated.

   ach = ActiveOrient::Query.new
    
   ach.queries << 'create class Contracts ABSTRACT'
   ach.queries << 'create property Contracts.subcategory link'
   ach.queries << 'create property Contracts.details link'
   ach.queries << 'create class Stocks extends Contracts'
   ach.queries << 'create class Futures extends Contracts'
   result = ach.execute_queries transaction: false
   
   

queries the database as demonstrated above. In addition, the generated query itself is added to the »queries«-Stack and the result can be found in sample_query.records.

This feature can be used as a substitute for simple functions

 roq = ActiveOrient::Query.new
 roq.queries =["select name, categories.subcategories.contracts from Industries  where name containstext     …'ial'"]
 roq.execute_queries.each{|x|  puts x.name, x.categories.inspect }
 --> Basic Materials 	[["#21:1"]]
 --> Financial  	[["#21:2"]]
 --> Industrial 	[["#23:0", "#23:1"]]

OrientDB supports the execution of SQL-Batch-Commands. ( http://orientdb.com/docs/2.0/orientdb.wiki/SQL-batch.html ) This is supported simply by using a Array as Argument for ActiveOrient::Query.queries

Therefor complex queries can be simplified using database-variables

   ach = ActiveOrient::Query.new
   ach.queries << [ "select expand( contracts )  from Openinterest"
	            "let con = select expand( contracts )  from Openinterest; ",
		    "...", ... ]
   result = ach.execute_queries 

The contract-documents are accessible with

  r.get_document '21:1'
  --><Stocks: con_id: 77680640 currency: EUR details: #18:1 exchange: SMART local_symbol: BAS 
     primary_exchange: IBIS subcategory: #14:1 symbol: BAS>

or

    my_query = ActiveOrient::Query.new
    ['Contracts', 'Industries', 'Categories', 'Subcategories'].each do |table|
        my_query.queries = [ "select count(*) from #{table}"]
 
        count = my_query.execute_queries
        # count=> [#<ActiveOrient::Model::Myquery:0x00000003b317c8 
        #		@metadata={"type"=>"d", "class"=>nil, "version"=>0, "fieldTypes"=>"count=l"},
        #		@attributes={"count"=>4 } ] --> an Array with one Element, therefor count.pop 
        puts "Table #{table} \t #{count.pop.count} Datasets "
    end
    -->Table Contracts 	 	56 Datasets 
    -->Table Industries 	 8 Datasets 
    -->Table Categories 	22 Datasets 
    -->Table Subcategories 	35 Datasets 

Note that the fetched Object is of type »Stocks« (ActiveOrient::Model::Stocks).

The ActiveOrient-API documentation can be found here: https://github.com/orientechnologies/orientdb-docs/wiki/OrientDB-ActiveOrient and the ActiveModel-documentation is here: http://www.rubydoc.info/gems/activemodel

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.