orientdb-time-graph 0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +58 -0
- data/Guardfile +24 -0
- data/LICENSE +21 -0
- data/README.md +221 -0
- data/VERSION +1 -0
- data/bin/console +75 -0
- data/config/boot.rb +119 -0
- data/config/config.yml +8 -0
- data/config/connect.yml +21 -0
- data/lib/init_db.rb +60 -0
- data/lib/orientdb_time_graph.rb +68 -0
- data/lib/setup.rb +40 -0
- data/lib/support.rb +38 -0
- data/lib/time_graph.rb +100 -0
- data/model/e.rb +7 -0
- data/model/tg/day_of.rb +3 -0
- data/model/tg/grid_of.rb +3 -0
- data/model/tg/jahr.rb +22 -0
- data/model/tg/monat.rb +57 -0
- data/model/tg/month_of.rb +0 -0
- data/model/tg/stunde.rb +16 -0
- data/model/tg/tag.rb +63 -0
- data/model/tg/time_base.rb +101 -0
- data/model/tg/time_of.rb +4 -0
- data/model/v.rb +123 -0
- data/orientdb_time_graph.gemspec +25 -0
- metadata +98 -0
data/config/config.yml
ADDED
data/config/connect.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
:orientdb:
|
3
|
+
:production:
|
4
|
+
:server: 172.28.50.25 # localhost
|
5
|
+
:user: hctw
|
6
|
+
:password: a***k
|
7
|
+
:database: o
|
8
|
+
:test:
|
9
|
+
:server: 10.222.148.109
|
10
|
+
:user: hctw
|
11
|
+
:password: s*p**
|
12
|
+
:database: test
|
13
|
+
:development:
|
14
|
+
:server: 10.222.148.109
|
15
|
+
:user: hctw
|
16
|
+
:password: s*p**
|
17
|
+
:database: demo
|
18
|
+
:port: 2480
|
19
|
+
:logger: stdout # 'file' or 'stdout'
|
20
|
+
|
21
|
+
# hfx: 101
|
data/lib/init_db.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module TG
|
2
|
+
module Setup
|
3
|
+
def self.init_database database_instance= V.db
|
4
|
+
stored_namespace = ActiveOrient::Model.namespace
|
5
|
+
ActiveOrient::Init.define_namespace { TG }
|
6
|
+
(logger= ActiveOrient::OrientDB.logger).progname= 'TG::Setup#InitDatabase'
|
7
|
+
# because edges are not resolved because of the namingconvention
|
8
|
+
tg_edges = [ :time_of, :day_of, :month_of, :grid_of ]
|
9
|
+
time_base_vertices = [ :stunde, :tag, :monat, :jahr ]
|
10
|
+
edges = V.db.class_hierarchy( base_class: 'E') & tg_edges.map( &:to_s )
|
11
|
+
vertices = V.db.class_hierarchy( base_class: 'tg_time_base' ) & time_base_vertices.map( &:to_s )
|
12
|
+
logger.info{ "affected-database-classes: \n #{ (vertices + edges).join(', ')}" }
|
13
|
+
|
14
|
+
delete_class = -> (c,d) do
|
15
|
+
the_class = ActiveOrient::Model.orientdb_class( name: c, superclass: d)
|
16
|
+
logger.info{ "The Class: "+the_class.to_s+ " removed from Database" }
|
17
|
+
the_class.delete_class
|
18
|
+
end
|
19
|
+
if defined?(TimeBase)
|
20
|
+
vertices.each{|v| delete_class[ v, :tg_time_base ] }
|
21
|
+
delete_class[ :tg_time_base, :V ]
|
22
|
+
end
|
23
|
+
|
24
|
+
logger.progname= 'TG::Setup#InitDatabase'
|
25
|
+
cleared_database = V.db.database_classes
|
26
|
+
logger.info{ " Creating Classes " }
|
27
|
+
V.create_class :time_base # --> TimeBase
|
28
|
+
# hour, day: month cannot be alloacated, because Day is a class of DateTime and thus is reserved
|
29
|
+
time_base_classes = TimeBase.create_class *time_base_vertices # --> Hour, Day, Month
|
30
|
+
TimeBase.create_property :value, type: :integer
|
31
|
+
#
|
32
|
+
## this puts an index on child-classes
|
33
|
+
time_base_classes.each{|c| c.create_index c.ref_name+'_value_idx' , type: :notunique, on: :value }
|
34
|
+
|
35
|
+
# modified naming-convention in model/e.rb
|
36
|
+
edges = E.create_class *tg_edges # --> TIME_OF, :DAY_OF
|
37
|
+
edges.each &:uniq_index
|
38
|
+
|
39
|
+
# restore namespace
|
40
|
+
ActiveOrient::Init.define_namespace { stored_namespace }
|
41
|
+
|
42
|
+
V.db.database_classes - cleared_database # return_value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
# to_do: define validations
|
47
|
+
# hour_class = r.create_vertex_class "Hour", properties: {value_string: {type: :string}, value: {type: :integer}}
|
48
|
+
# hour_class.alter_property property: "value", attribute: "MIN", alteration: 0
|
49
|
+
# hour_class.alter_property property: "value", attribute: "MAX", alteration: 23
|
50
|
+
#
|
51
|
+
# day_class = r.create_vertex_class "Day", properties: {value_string: {type: :string}, value: {type: :integer}}
|
52
|
+
# day_class.alter_property property: "value", attribute: "MIN", alteration: 1
|
53
|
+
# day_class.alter_property property: "value", attribute: "MAX", alteration: 31
|
54
|
+
#
|
55
|
+
# month_class = r.create_vertex_class "Month", properties: {value_string: {type: :string}, value: {type: :integer}}
|
56
|
+
# month_class.alter_property property: "value", attribute: "MIN", alteration: 1
|
57
|
+
# month_class.alter_property property: "value", attribute: "MAX", alteration: 12
|
58
|
+
#
|
59
|
+
|
60
|
+
# timeof_class = r.create_edge_class "TIMEOF"
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'active-orient'
|
2
|
+
require_relative 'time_graph.rb'
|
3
|
+
require_relative 'support.rb'
|
4
|
+
|
5
|
+
require_relative 'init_db'
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module TG
|
10
|
+
|
11
|
+
# completes the parameter for calling ActiveOrient::Init.connect
|
12
|
+
#
|
13
|
+
# Is called from connect only if ActiveOrient.default_server is not set previously
|
14
|
+
#
|
15
|
+
# otherwise the credentials from the main-activeorient-instance are used.
|
16
|
+
def self.set_defaults **login
|
17
|
+
c = { :server => 'localhost',
|
18
|
+
:port => 2480,
|
19
|
+
:protocol => 'http',
|
20
|
+
:user => 'root',
|
21
|
+
:password => 'root',
|
22
|
+
:database => 'temp'
|
23
|
+
}.merge login
|
24
|
+
|
25
|
+
ActiveOrient.default_server= { user: c[:user], password: c[:password] ,
|
26
|
+
server: c[:server], port: c[:port] }
|
27
|
+
ActiveOrient.database = c[:database]
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.connect **login
|
31
|
+
project_root = File.expand_path('../..', __FILE__)
|
32
|
+
set_defaults( **login) unless ActiveOrient.default_server.is_a?(Hash) && ActiveOrient.default_server[:user].present?
|
33
|
+
ActiveOrient::Init.define_namespace { TG }
|
34
|
+
# a provided block is used to introduce additional locations of model-files
|
35
|
+
the_model_dirs = block_given? ? [ "#{project_root}/model", yield].flatten : [ "#{project_root}/model" ]
|
36
|
+
ActiveOrient::OrientDB.new preallocate: true, model_dir: the_model_dirs
|
37
|
+
@time_graph = TG.const_defined?(:TIME_OF) ? TG::TIME_OF.count > 0 : nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.time_graph?
|
41
|
+
@time_graph
|
42
|
+
end
|
43
|
+
def self.check_and_initialize database_instance
|
44
|
+
if database_instance.get_classes( "name").values.flatten.include? 'time_base'
|
45
|
+
return true
|
46
|
+
else
|
47
|
+
TG::Setup.init_database database_instance
|
48
|
+
puts "Database-Structure allocated"
|
49
|
+
puts "Exiting now, please restart and call »TG::TimeGraph.populate«"
|
50
|
+
Kernel.exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.info
|
55
|
+
puts "-------------- TIME GRAPH ------------------"
|
56
|
+
puts "Allocated Years : "
|
57
|
+
puts TG::Jahr.all.map(&:value).sort.join('; ')
|
58
|
+
puts ""
|
59
|
+
puts "Type: #{TG::Stunde.all.empty? ? "Date-Graph" : "DateTime-Graph"}"
|
60
|
+
puts ""
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
|
data/lib/setup.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
#require 'bunny'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active-orient'
|
4
|
+
require 'yaml'
|
5
|
+
require_relative 'orientdb_time_graph'
|
6
|
+
#require 'dry/core/class_attributes'
|
7
|
+
#require_relative "logging"
|
8
|
+
require_relative "init_db"
|
9
|
+
|
10
|
+
|
11
|
+
module TG
|
12
|
+
|
13
|
+
## Standalone setup
|
14
|
+
##
|
15
|
+
## initializes ActiveOrient and adds time-graph database-classes
|
16
|
+
## through namespace
|
17
|
+
#
|
18
|
+
# valid environments: :test, :development, :production
|
19
|
+
def self.setup environment = :test
|
20
|
+
|
21
|
+
read_yml = -> (key) do
|
22
|
+
YAML::load_file( File.expand_path('../../config/connect.yml',__FILE__))[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
logon = read_yml[:orientdb][environment]
|
27
|
+
|
28
|
+
ActiveOrient::Init.connect **logon
|
29
|
+
TG.connect **logon
|
30
|
+
# we have to initialise the timegraph at this point, otherwise any
|
31
|
+
# manual requirement fails.
|
32
|
+
unless ActiveOrient::Model.namespace.send :const_defined?, 'Tag'
|
33
|
+
Setup.init_database V.orientdb
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
end
|
data/lib/support.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
## We are defining to_tg methods for Strings, Date and DateTiem objects.
|
2
|
+
## Strings are converted to the time format.
|
3
|
+
#
|
4
|
+
class Date
|
5
|
+
def to_tg
|
6
|
+
# old method performed queries
|
7
|
+
# Date.today.to_tg
|
8
|
+
# INFO->select from tg_jahr where value = 2019
|
9
|
+
# INFO->select expand (out_tg_month_of.in[value = 4]) from #117:0
|
10
|
+
# INFO->select expand (out_tg_day_of.in[value = 2]) from #108:6
|
11
|
+
#
|
12
|
+
# the alternative:
|
13
|
+
# TG::Jahr[year].monat(month).tag(day).orient_flatten
|
14
|
+
# which can be combined through
|
15
|
+
# query "select expand (out_tg_day_of.in[value = #{day}]) from (select expand (out_tg_month_of.in[value = #{month}]) from (select from tg_jahr where value = #{year} ) ) "
|
16
|
+
#
|
17
|
+
# this is realized in fetch
|
18
|
+
TG::Tag.fetch self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class DateTime
|
23
|
+
def to_tg
|
24
|
+
if TG.time_graph?
|
25
|
+
TG::Monat[month].tag(day).stunde(hour).pop.pop
|
26
|
+
else
|
27
|
+
TG::Tag.fetch self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class String
|
33
|
+
def to_tg
|
34
|
+
date = DateTime.parse(self)
|
35
|
+
date.to_tg
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/lib/time_graph.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
#require 'time'
|
2
|
+
|
3
|
+
module TG
|
4
|
+
|
5
|
+
class TimeGraph
|
6
|
+
class << self # singleton class
|
7
|
+
## we populate the graph with a 1:n-Layer
|
8
|
+
# (year -->) n[month] --> n[day] ( --> n[hour] ])
|
9
|
+
# thus creating edges is providing a static :from-vertex to numerous :to-vertices
|
10
|
+
# the to:vertices are first created and fenced in an array. Then all edges are created at once.
|
11
|
+
# In Rest-Mode this is much quicker.
|
12
|
+
def populate years = (1900 .. 2050), delete: true
|
13
|
+
|
14
|
+
count_gridspace = -> do
|
15
|
+
[TG::Jahr,TG::Monat,TG::Tag,TG::Stunde].map{|x| "#{x.ref_name} -> #{x.count}" }
|
16
|
+
end
|
17
|
+
|
18
|
+
if delete
|
19
|
+
puts count_gridspace[].join('; ')
|
20
|
+
puts "deleting content"
|
21
|
+
[TG::Jahr,TG::Monat,TG::Tag,TG::Stunde].each{|x| x.delete all: true}
|
22
|
+
puts "checking .."
|
23
|
+
puts count_gridspace[].join('; ')
|
24
|
+
end
|
25
|
+
|
26
|
+
kind_of_grid = if years.is_a? Range
|
27
|
+
'daily'
|
28
|
+
else
|
29
|
+
years = years.is_a?(Fixnum) ? [years]: years
|
30
|
+
'hourly'
|
31
|
+
end
|
32
|
+
|
33
|
+
### switch logger level
|
34
|
+
previous_looger_level = V.db.logger.level
|
35
|
+
V.db.logger.level = 2
|
36
|
+
### NOW WHERE THE DATABASE IS CLEAN, POPULATE IT WITH A DAILY GRID
|
37
|
+
print "Grid: "
|
38
|
+
year_grid, month_grid, day_grid, hour_grid = nil
|
39
|
+
years.each do | the_year |
|
40
|
+
year_vertex = TG::Jahr.create value: the_year
|
41
|
+
# puts "YEAR_GRID: #{year_grid.inspect}"
|
42
|
+
TG::GRID_OF.create( from: year_grid , to: year_vertex ) if year_grid.present?
|
43
|
+
year_grid = year_vertex
|
44
|
+
month_vertices = ( 1 .. 12 ).map do | the_month |
|
45
|
+
month_vertex= TG::Monat.create value: the_month
|
46
|
+
TG::GRID_OF.create( from: month_grid , to: month_vertex ) if month_grid.present?
|
47
|
+
month_grid = month_vertex
|
48
|
+
last_month_day = (Date.new( the_year, the_month+1, 1)-1).day rescue 31 # rescue covers month > 12
|
49
|
+
day_vertices = ( 1 .. last_month_day ).map do | the_day |
|
50
|
+
day_vertex = TG::Tag.create value: the_day
|
51
|
+
TG::GRID_OF.create( from: day_grid , to: day_vertex ) if day_grid.present?
|
52
|
+
day_grid = day_vertex
|
53
|
+
if kind_of_grid == 'hourly'
|
54
|
+
hour_vertices = (0 .. 23).map do |h|
|
55
|
+
hour_vertex = Stunde.create( value: h)
|
56
|
+
|
57
|
+
TG::GRID_OF.create( from: hour_grid , to: hour_vertex ) if hour_grid.present?
|
58
|
+
hour_grid = hour_vertex
|
59
|
+
hour_vertex # return_value
|
60
|
+
end
|
61
|
+
TG::TIME_OF.create from: day_vertex, to: hour_vertices
|
62
|
+
end
|
63
|
+
day_vertex # return_value
|
64
|
+
end
|
65
|
+
TG::DAY_OF.create from: month_vertex, to: day_vertices
|
66
|
+
month_vertex # return_value
|
67
|
+
end
|
68
|
+
print "#{the_year} "
|
69
|
+
TG::MONTH_OF.create from: year_vertex, to: month_vertices
|
70
|
+
end
|
71
|
+
print "\n"
|
72
|
+
V.db.logger.level = previous_looger_level
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end # class
|
76
|
+
end # Module
|
77
|
+
## here we start if the file is called from the command-lind
|
78
|
+
if $0 == __FILE__
|
79
|
+
require './config/boot'
|
80
|
+
#TG::Setup.init_database # --> config/init_db
|
81
|
+
TG::TimeGraph.populate
|
82
|
+
|
83
|
+
|
84
|
+
print "\n" * 4
|
85
|
+
puts '-' * 40
|
86
|
+
puts "Features of the DateTime Graph"
|
87
|
+
puts '-' * 40
|
88
|
+
puts
|
89
|
+
puts "Allocated Month => Monat.first.value:\t\t" + Monat.first.value.to_s
|
90
|
+
puts
|
91
|
+
puts "Adressing Days => Monat.first.tag[2].value:\t" + Monat.first.tag[2].value.to_s
|
92
|
+
puts
|
93
|
+
puts "Display Date => Monat.first.tag[13].datum:\t"+ Monat.first.tag[13].datum.to_s
|
94
|
+
|
95
|
+
puts "Display next Date => Monat.first.tag[13].next.datum:\t"+ Monat.first.tag[13].next.datum.to_s
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
end
|
data/model/e.rb
ADDED
data/model/tg/day_of.rb
ADDED
data/model/tg/grid_of.rb
ADDED
data/model/tg/jahr.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
class TG::Jahr #< TG::TimeBase
|
3
|
+
def der_monat m
|
4
|
+
m >0 && m<13 ? out_tg_month_of[m].in : nil
|
5
|
+
end
|
6
|
+
|
7
|
+
# returns an array of days
|
8
|
+
# thus enables the use as
|
9
|
+
# Monat[9].tag[9]
|
10
|
+
def monat *key
|
11
|
+
if key.blank?
|
12
|
+
out_tg_month_of.in
|
13
|
+
else
|
14
|
+
key= key.first if key.is_a?(Array) && key.size == 1
|
15
|
+
# out_tg_month_of[key].in
|
16
|
+
nodes( :out, via: /month/ , where: { value: key } )
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
end
|
22
|
+
|
data/model/tg/monat.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
class TG::Monat # < TG::TimeBase
|
2
|
+
# starts at a given month-entry
|
3
|
+
# tg_monat.in tg_month_of out --> tg_jahr
|
4
|
+
def _jahr
|
5
|
+
query.nodes :in, via: TG::MONTH_OF
|
6
|
+
end
|
7
|
+
def der_tag d
|
8
|
+
# d=d-1
|
9
|
+
d >0 && d<31 ? out_tg_day_of[d].in : nil
|
10
|
+
end
|
11
|
+
|
12
|
+
# returns an array of days
|
13
|
+
# thus enables the use as
|
14
|
+
# Monat[9].tag[9]
|
15
|
+
def tag *key
|
16
|
+
if key.blank?
|
17
|
+
out_tg_day_of.in
|
18
|
+
else
|
19
|
+
# out_tg_day_of.in
|
20
|
+
key= key.first if key.size == 1
|
21
|
+
nodes( :out, via: /day/ , where: { value: key } )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns the specified edge
|
26
|
+
# i.e. Monat[9]
|
27
|
+
#
|
28
|
+
|
29
|
+
def jahr
|
30
|
+
_jahr.execute.first
|
31
|
+
# in_tg_month_of.out.first
|
32
|
+
end
|
33
|
+
|
34
|
+
# returns the absolute Month-Value
|
35
|
+
#
|
36
|
+
# enables easy calculations betwwen month-vertices
|
37
|
+
#
|
38
|
+
# i.e. TG::Jahr[2013].monat(4).abs_value.first - TG::Jahr[2012].monat(9).abs_value.first
|
39
|
+
# => 7
|
40
|
+
def abs_value
|
41
|
+
jahr.value * 12 + value
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.fetch datum , &b # parameter: a date
|
45
|
+
# query_database( "select expand (out_tg_day_of.in[value = #{datum.day}]) from (select expand (out_tg_month_of.in[value = #{datum.month}]) from (select from tg_jahr where value = #{datum.year} ) ) ") &.first
|
46
|
+
q = OrientSupport::OrientQuery.new from: TG::Jahr, where: { value: datum.year }
|
47
|
+
w = OrientSupport::OrientQuery.new from: q
|
48
|
+
w.nodes :out, via: TG::MONTH_OF, where: { value: datum.month }
|
49
|
+
|
50
|
+
query_database( w, &b).first
|
51
|
+
end
|
52
|
+
|
53
|
+
#TG::Monat.fetch Date.new(2000,4,5)
|
54
|
+
#21.06.(06:29:11) INFO->select expand ( outE('tg_month_of').in[ value = 4 ] ) from ( select from tg_jahr where value = 2000 )
|
55
|
+
# => #<TG::Monat:0x00000000032fbe28 @metadata={:type=>"d", :class=>"tg_monat", :version=>34, :fieldTypes=>"out_tg_day_of=g,in_tg_month_of=g,in_tg_grid_of=g,out_tg_grid_of=g", :cluster=>132, :record=>225, :edges=>{:in=>["tg_month_of", "tg_grid_of"], :out=>["tg_day_of", "tg_grid_of"]}}, @d=nil, @attributes={:out_tg_day_of=>["#158:6859", "#159:6859", "#160:6859", "#153:6860", "#154:6860", "#155:6860", "#156:6860", "#157:6860", "#158:6860", "#159:6860", "#160:6860", "#153:6861", "#154:6861", "#155:6861", "#156:6861", "#157:6861", "#158:6861", "#159:6861", "#160:6861", "#153:6862", "#154:6862", "#155:6862", "#156:6862", "#157:6862", "#158:6862", "#159:6862", "#160:6862", "#153:6863", "#154:6863", "#155:6863"], :in_tg_month_of=>["#164:225"], :value=>4, :in_tg_grid_of=>["#173:7103"], :out_tg_grid_of=>["#172:7107"]}>
|
56
|
+
|
57
|
+
end
|
File without changes
|
data/model/tg/stunde.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
class TG::Stunde # < TG::TimeBase
|
2
|
+
|
3
|
+
def tag
|
4
|
+
in_tg_time_of.out
|
5
|
+
end
|
6
|
+
|
7
|
+
def datum
|
8
|
+
month = in_tg_time_of.out.in_tg_day_of.out.value
|
9
|
+
day = in_tg_time_of.out.value
|
10
|
+
"#{day.first}.#{month.flatten.first}.#{Date.today.year} #{value}:00"
|
11
|
+
end
|
12
|
+
def next
|
13
|
+
puts value.inspect
|
14
|
+
in_tg_day_of.out.first.tag( value + 1 )
|
15
|
+
end
|
16
|
+
end
|