orientdb-time-graph 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ ---
2
+ :active_orient:
3
+ ## Namespace: Prefix of Model-Objects. :self -> ActiveOrient::Model::{name}
4
+ ## :object => No Prefix
5
+ ## :active_orient => ActiveOrient::{name}
6
+ :namespace: :object
7
+ :model_dir: 'model'
8
+
@@ -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
@@ -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
+
@@ -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
@@ -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
+
@@ -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
@@ -0,0 +1,7 @@
1
+
2
+ class E #< ActiveOrient::Model
3
+ def self.naming_convention name=nil
4
+ name.present? ? name.upcase : ref_name.upcase
5
+ end
6
+ end
7
+
@@ -0,0 +1,3 @@
1
+ class TG::DAY_OF
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ class TG::GRID_OF
2
+
3
+ end
@@ -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
+
@@ -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
@@ -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