orientdb-time-graph 0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|