arcadedb 0.3.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/bin/+ ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ ## loads the active-orient environment
3
+ ## and starts an interactive shell
4
+ ##
5
+ ## Parameter:
6
+ ## production (p)
7
+ ## development (d) [default]
8
+ ## test (t)
9
+ require 'bundler/setup'
10
+ require 'yaml'
11
+ require 'logger'
12
+ require 'pastel'
13
+ require 'terminal-table'
14
+ require 'arcade'
15
+ #begin
16
+
17
+ module CoreExtensions
18
+
19
+ module Hash
20
+ module TablePresenter
21
+ def table_header
22
+ keys
23
+ end
24
+ def table_row
25
+ values
26
+ end
27
+ end
28
+ end
29
+
30
+ module Array
31
+ module TablePresenter
32
+ def as_table(&b)
33
+ the_table_header = first.table_header(&b)
34
+ the_table_rows = map &:table_row
35
+ Terminal::Table.new headings: the_table_header, rows: the_table_rows , style: { border: :unicode }
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ Array.include CoreExtensions::Array::TablePresenter
42
+ Hash.include CoreExtensions::Hash::TablePresenter
43
+
44
+
45
+ read_yml = -> (key) do
46
+ YAML::load_file( File.expand_path('../../config.yml',__FILE__) )[key]
47
+ end
48
+ def list_types db= Arcade::Api.databases.first
49
+ list= Arcade::Api.query(db){ "select from schema:types" }
50
+ puts "list: #{list}"
51
+ output = Terminal::Table.new do |t|
52
+ t.title = "database: #{db}"
53
+ t.headings = ["Name" , "Parents", "Type", 'Properties','Unique', 'Automatic']
54
+ t.style = { :border => :markdown }
55
+ list.each do |row|
56
+ t.add_row [ row['name'],row['parent_types'],row['type'] ]
57
+ if !row['indexes'].empty?
58
+ t.add_separator
59
+ row['indexes'].each do |i|
60
+ t.add_row [i['name'], i['typeName'], i['type'],i['properties'], i['unique'],i['automatic'] ]
61
+ end
62
+ end
63
+ if !row['properties'].empty?
64
+ t.add_separator
65
+ row['properties'].each do |p|
66
+ t.add_row[p['name'],p['id'],p['type']]
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+
74
+
75
+
76
+
77
+ include Arcade
78
+
79
+ puts "-"*80
80
+ puts "--- Namespace Arcade is included "
81
+ puts ""
82
+ puts " Available ArcadeDB-Statements"
83
+ puts " ----------------------------"
84
+ puts " Api.databases # returns an Array of known databases "
85
+ puts " Api.create_database <a string> # returns true if succesfull "
86
+ puts " Api.drop_database <a string> "
87
+ puts ""
88
+ puts " Create and fetch documents and vertices"
89
+ puts " ----------------------------"
90
+ puts " Api.create_document <database>, <type>, attribute: value , ... "
91
+ puts " Api.get_record <database>, <rid> # returns a hash "
92
+ puts ""
93
+ puts " submit queries"
94
+ puts " ----------------------------"
95
+ puts " Api.execute( <database> ) { <query> } #submit query as block"
96
+ puts " Api.query( <database> ) { <query> } "
97
+ puts ""
98
+ puts "-"*80
99
+ puts ""
100
+ #C = Arcade::Database.new
101
+ #D = MiniSql::Connection.get( C.connection, {} )
102
+ #require 'pry'
103
+ require 'irb'
104
+ ARGV.clear
105
+ IRB.start(__FILE__)
106
+ #Pry.start(__FILE__)
data/bin/console ADDED
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby
2
+ ## loads the active-orient environment
3
+ ## and starts an interactive shell
4
+ ##
5
+ ## Parameter:
6
+ ## production (p)
7
+ ## development (d) [default]
8
+ ## test (t)
9
+ require 'bundler/setup'
10
+ require 'terminal-table'
11
+ require 'zeitwerk'
12
+ require 'pastel'
13
+ require 'arcade'
14
+ require 'pry'
15
+ #begin
16
+
17
+
18
+ def browse db: Arcade::Api.databases.first , extended: false
19
+
20
+ headings = -> do
21
+ ar= ["","Name" , "Parents", "Type","Properties", 'Unique', 'Automatic']
22
+ extended ? ar : ar - ['Properties']
23
+ end
24
+ rows = ->(r) do
25
+ ar=["Type", r[:name],r[:parent_types],r[:type]," " , " "]
26
+ !extended ? ar : ar + [""]
27
+ end
28
+ indizes = ->(i) do
29
+ if extended
30
+ ["Index",i[:name], "on #{i[:typeName]}", i[:type],i[:properties], i[:unique],i[:automatic] ]
31
+ else
32
+ ["Index",i[:name], "", i[:type], i[:unique],i[:automatic] ]
33
+ end
34
+ end
35
+
36
+ list= Arcade::Api.query db, "select from schema:types"
37
+ if list.is_a? Array
38
+ Terminal::Table.new do |t|
39
+ add_additional_separator =false
40
+ t.title = "Database: #{db}"
41
+ t.headings = headings.call
42
+ # t.style = { :border => :markdown }
43
+ t.style = { border: :unicode_thick_edge }
44
+ list.each.with_index do |row,j|
45
+ t.add_separator if (add_additional_separator || !row[:indexes].empty? || !row[:properties].empty?) && j >0
46
+ add_additional_separator =false
47
+ t.add_row rows[row]
48
+ if !row[:indexes].empty?
49
+ add_additional_separator = true
50
+ row[:indexes].each do |i|
51
+ t.add_row indizes[i]
52
+ end
53
+ end
54
+ if !row[:properties].empty?
55
+ add_additional_separator = true
56
+ row[:properties].each do |p|
57
+ ar= ["Property",p[:name],"",p[:type]," "," "]
58
+ t.add_row !extended ? ar : ar + [""]
59
+ end
60
+ end
61
+ end
62
+ end
63
+ else
64
+ list
65
+ end
66
+ end
67
+
68
+
69
+
70
+
71
+
72
+
73
+ include Arcade
74
+
75
+ def help
76
+ p = Pastel.new
77
+ c = p.bright_white.bold.on_yellow.detach
78
+ g = p.green.on_black.detach
79
+ puts "-"*80
80
+ puts " Namespace is: Arcade ! "
81
+ puts ""
82
+ puts c[" Essential ArcadeDB-Statements "]
83
+ puts " ----------------------------"
84
+ puts g[" Api.databases "]+" # returns an Array of known databases "
85
+ puts g[" Api.create_database <a string> "] + " # returns true if successfull "
86
+ puts g[" Api.drop_database <a string> "]
87
+ puts ""
88
+ puts " Create and fetch documents and vertices"
89
+ puts " ----------------------------"
90
+ puts g[" Api.create_document <database>, <type>, attribute: value , ... "]
91
+ puts g[" Api.get_record <database>, <rid> "] +"# returns a hash "
92
+ puts ""
93
+ puts " submit queries"
94
+ puts " ----------------------------"
95
+ puts g[" Api.execute( <database> ) { <query> } "]+" #submit query as block"
96
+ puts g[" Api.query <database> , <query> "]
97
+ puts ""
98
+ puts " -----------------------------"
99
+ puts " Display the database-structure"
100
+ puts g[" puts browse db: \"name\", extended: \"false|true\" "]+ "browses the first database found, "
101
+ puts " if called without parameters"
102
+ puts " Display this helpscreen: "+ g["help"]
103
+ puts "-"*80
104
+ puts ""
105
+ end
106
+
107
+ help
108
+ e= ARGV.empty? ? :development : ARGV.last.downcase.to_sym
109
+ ## load test model files
110
+ #require "#{__dir__}/../spec/model_helper"
111
+
112
+ loader = Zeitwerk::Loader.new
113
+ loader.push_dir ("#{__dir__}/../spec/model")
114
+ loader.setup
115
+ puts "DB = Arcade::Database-instance"
116
+ DB = Arcade::Init.connect e
117
+ #require 'pry'
118
+ require 'irb'
119
+ ARGV.clear
120
+ #begin
121
+ #IRB.start(__FILE__)
122
+ #rescue ArgumentError => e
123
+ # puts e
124
+ ## retry
125
+ #end
126
+ Pry.start(__FILE__)
data/examples/books.rb ADDED
@@ -0,0 +1,139 @@
1
+ =begin
2
+ Books Example
3
+
4
+ There are several Books. And there is a Table with Keywords. These are our Vertex-Classes
5
+
6
+ The Keywords are associated to the books, this is realized via an Edge »has_content«
7
+
8
+ This Example demonstrates how create a simple graph:
9
+
10
+ Book --> HasContent --> KeyWord
11
+
12
+ and to query it dynamically using Arcade::Query
13
+
14
+ The model-files are located in `/spec/model/ex`
15
+
16
+ There are 3 default search items provided. They are used if no parameter is given.
17
+ However, any parameter given is transmitted as serach-criteria, ie.
18
+ ruby books.rb Juli August
19
+ defines two search criteria.
20
+
21
+ =end
22
+ require 'bundler/setup'
23
+ require 'yaml'
24
+ require 'zeitwerk'
25
+ require 'arcade'
26
+
27
+ include Arcade
28
+ ## require modelfiles
29
+ loader = Zeitwerk::Loader.new
30
+ loader.push_dir ("#{__dir__}/../spec/model")
31
+ loader.setup
32
+
33
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
34
+ ################# read samples ##############
35
+ def read_samples
36
+ print "\n === READ SAMPLES === \n"
37
+ ## Lambda fill databasea
38
+ # Anaylse a sentence
39
+ # Split into words and upsert them to Word-Class.
40
+ # The Block is only performed, if a new Word is inserted.
41
+ fill_database = ->(sentence, this_book ) do
42
+
43
+ sentence.split(' ').map do | word |
44
+ this_book.assign vertex: Ex::Keyword.create( item: word ), via: Ex::HasContent if Ex::Keyword.where( item: word ).empty?
45
+ end
46
+
47
+ end
48
+ ## Lambda end
49
+ words = 'Die Geschäfte in der Industrie im wichtigen US-Bundesstaat New York sind im August so schlecht gelaufen wie seit mehr als sechs Jahren nicht mehr Der entsprechende Empire-State-Index fiel überraschend von plus Punkten im Juli auf minus 14,92 Zähler Dies teilte die New Yorker Notenbank Fed heute mit. Bei Werten im positiven Bereich signalisiert das Barometer ein Wachstum Ökonomen hatten eigentlich mit einem Anstieg auf 5,0 Punkte gerechnet'
50
+ this_book = Ex::Book.create title: 'first'
51
+ fill_database[ words, this_book ]
52
+
53
+ words2 = 'Das Bruttoinlandsprodukt BIP in Japan ist im zweiten Quartal mit einer aufs Jahr hochgerechneten Rate von Prozent geschrumpft Zu Jahresbeginn war die nach den USA und China drittgrößte Volkswirtschaft der Welt noch um Prozent gewachsen Der Schwächeanfall wird auch als Rückschlag für Ministerpräsident Shinzo Abe gewertet der das Land mit einem Mix aus billigem Geld und Konjunkturprogramm aus der Flaute bringen will Allerdings wirkte sich die heutige Veröffentlichung auf die Märkten nur wenig aus da Ökonomen mit einem schwächeren zweiten Quartal gerechnet hatten'
54
+ this_book = Ex::Book.create title: 'second'
55
+ fill_database[ words2, this_book ]
56
+ puts "#{Ex::Keyword.count} keywords inserted into Database"
57
+ end
58
+
59
+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
60
+ ################# display books ##############
61
+ def display_books_with *desired_words
62
+ ## Each serach criteria becomes a subquery
63
+ ## This is integrated into the main_query using 'let'.
64
+ ## Subquery: let ${a-y} = select expand(in('has_content')) from keyword where item = {search_word}
65
+ ## combine with intercect: $z = Intercect( $a ... $y )
66
+ ## Main Query is just
67
+ ## select expand( $z ) followed by all let-statements and finalized by "intercect"
68
+ #
69
+
70
+ # lambda to create subqueries
71
+ word_query = -> (arg) do
72
+ q= Ex::Keyword.query where: arg
73
+ q.nodes :in, via: Ex::HasContent
74
+ end
75
+
76
+ main_query = Arcade::Query.new
77
+
78
+ ## We just create "select expand($z)"
79
+ ## without 'expand' the result is "$z" -> "in(ex_has_content)"-> [ book-record ]
80
+ ## with 'expand' its "in(ex_has_content)"-> [ book-record ]
81
+ main_query.expand( '$z' )
82
+
83
+
84
+ print("\n === display_books_with » #{ desired_words.join "," } « === \n")
85
+
86
+ intersects = Array.new
87
+ ## Now, add subqueries to the main-query
88
+ desired_words.each_with_index do | word, i |
89
+ symbol = ( i+97 ).chr # convert 1 -> 'a', 2 -> 'b' ...
90
+ main_query.let symbol => word_query[ item: word ]
91
+ intersects << "$#{symbol}"
92
+ end
93
+ ## Finally add the intersects statement
94
+ ## Use UnionAll for an superposition of positive seraches
95
+ ## Use Intercept for a positive search only if all parameters apply to one book.
96
+ #
97
+ main_query.let "$z = unionall(#{intersects.join(', ')}) "
98
+ #main_query.let "$z = Intersect(#{intersects.join(', ')}) "
99
+ puts "generated Query:"
100
+ puts main_query.to_s
101
+ puts "\n\n\n"
102
+ result = main_query.query.select_result
103
+ puts '-' * 23
104
+ print "found books: "
105
+ puts result.map( &:title ).uniq.join("; ")
106
+ if result.empty?
107
+ puts " -- None -- "
108
+ puts " try » ruby books.rb Japan Flaute « for a positive search in one of the two sentences"
109
+ else
110
+ puts '-_' * 23
111
+ puts "that's it folks"
112
+ end
113
+ end
114
+
115
+ if $0 == __FILE__
116
+
117
+ search_items = ARGV.empty? ? ['China', 'aus', 'Flaute'] : ARGV
118
+
119
+ ## clear test database
120
+ databases = Arcade::Api.databases
121
+ if databases.include?(Arcade::Config.database[:test])
122
+ Arcade::Api.drop_database Arcade::Config.database[:test]
123
+ end
124
+ Arcade::Api.create_database Arcade::Config.database[:test]
125
+
126
+ Arcade::Init.connect 'test'
127
+
128
+ print "\n === REBUILD finished=== \n"
129
+ ## check wether the database tables exist. Then delete Database-Class and preallocated ruby-Object
130
+ print " creating Book and Keyword as Vertex; HasContent as Edge \n"
131
+ Ex::Book.create_type
132
+ Ex::Keyword.create_type
133
+ Ex::HasContent.create_type
134
+ print "\n === PROPERTY === \n"
135
+
136
+ read_samples
137
+ display_books_with *search_items
138
+
139
+ end
@@ -0,0 +1,149 @@
1
+ ##
2
+ ## This example realises an unidirectional Graph using
3
+ ## a document database primitve and a self referencing 1:1 relation.
4
+ #
5
+ ## Modelfiles are located in spec/model.
6
+ ## The exampmle runs in the test environment.
7
+ ##
8
+ require 'bundler/setup'
9
+ require 'zeitwerk'
10
+ require 'arcade'
11
+
12
+ include Arcade # Arcade Namespace is optional
13
+ ## require modelfiles
14
+ loader = Zeitwerk::Loader.new
15
+ loader.push_dir ("#{__dir__}/../spec/model")
16
+ loader.setup
17
+
18
+ ## clear test database
19
+
20
+ databases = Api.databases
21
+ if databases.include?(Config.database[:test])
22
+ Api.drop_database Config.database[:test]
23
+ end
24
+ Api.create_database Config.database[:test]
25
+
26
+ ## Universal Database handle
27
+ DB = Init.connect 'test'
28
+
29
+ ## ------------------------------------------------------ End Setup ------------------------------------- ##
30
+ ##
31
+ ## We are realising a self referencing relation
32
+ ## name --> child
33
+ #
34
+ # database schema
35
+ # CREATE DOCUMENT TYPE ex_names
36
+ # CREATE PROPERTY ex_names.child LINK
37
+ # CREATE PROPERTY ex_names.name STRING
38
+ # CREATE INDEX `Example[names]` ON ex_names ( name ) UNIQUE
39
+
40
+
41
+ # Namespace for Data-Objects is `Ex`
42
+ Ex::Names.create_type # initialize the database
43
+ # spec/models/ex/names.rb
44
+ # Put some names into the database
45
+ puts "-------------------- insert data ---------------------------------"
46
+ table = %w( Guthorn Fulkerson Sniezek Tomasulo Portwine Keala Revelli Jacks Gorby Alcaoa ).map do | name |
47
+ Ex::Names.insert name: name, age: rand(99)
48
+ end
49
+ # Connect randomly
50
+ children = (0..6).map{ | i | table[-i].rid }
51
+ table.each{| n | n.update child: table[ rand(10)].rid }
52
+
53
+ puts "-------------------- raw data ---------------------------------"
54
+ puts Ex::Names.all autoload: false # display links as rid (do not load the document)
55
+
56
+ puts "--------------- Parent and Children ---------------------------"
57
+
58
+ ## Create a Query-Object and execute it via `query`
59
+ children_query = Ex::Names.query projection: ['name', 'child.name']
60
+ puts children_query.query
61
+
62
+ puts "--------------- unidirectional relation -----------------------"
63
+
64
+ ## Use the `Model.all` approach instead
65
+ puts Ex::Names.all projection: ['name as parent',
66
+ 'age as parent_age',
67
+ 'child.age',
68
+ 'child.child.age as second_generation_age'],
69
+ order: 'parent_age'
70
+
71
+
72
+ puts "----------------- query relation - teenager -------------------"
73
+
74
+ teenager_query = Ex::Names.query projection: ['name as parent',
75
+ 'child:{name, age} as teenager'],
76
+ where: 'child.age between 10 and 25'
77
+
78
+ puts teenager_query.query
79
+
80
+ __END__
81
+
82
+ Expected result
83
+
84
+ 24.04.(11:12:58) INFO->Q: create document type ex_names
85
+ 24.04.(11:12:58) INFO->Q: CREATE PROPERTY ex_names.child LINK
86
+ 24.04.(11:12:58) INFO->Q: CREATE PROPERTY ex_names.name STRING
87
+ 24.04.(11:12:58) INFO->Q: CREATE INDEX `Example[names]` ON ex_names ( name ) UNIQUE
88
+ -------------------- insert data ---------------------------------
89
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Guthorn","age":81}
90
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Fulkerson","age":16}
91
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Sniezek","age":50}
92
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Tomasulo","age":20}
93
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Portwine","age":7}
94
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Keala","age":57}
95
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Revelli","age":31}
96
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Jacks","age":23}
97
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Gorby","age":83}
98
+ 24.04.(11:12:58) INFO->Q: INSERT INTO ex_names CONTENT {"name":"Alcaoa","age":58}
99
+ 24.04.(11:12:58) INFO->Q: update #1:0 set child = '#2:1' return after $current
100
+ 24.04.(11:12:58) INFO->Q: update #2:0 set child = '#3:0' return after $current
101
+ 24.04.(11:12:58) INFO->Q: update #3:0 set child = '#1:0' return after $current
102
+ 24.04.(11:12:58) INFO->Q: update #4:0 set child = '#1:1' return after $current
103
+ 24.04.(11:12:58) INFO->Q: update #5:0 set child = '#2:1' return after $current
104
+ 24.04.(11:12:58) INFO->Q: update #6:0 set child = '#2:1' return after $current
105
+ 24.04.(11:12:58) INFO->Q: update #7:0 set child = '#8:0' return after $current
106
+ 24.04.(11:12:58) INFO->Q: update #8:0 set child = '#6:0' return after $current
107
+ 24.04.(11:12:58) INFO->Q: update #1:1 set child = '#4:0' return after $current
108
+ 24.04.(11:12:58) INFO->Q: update #2:1 set child = '#1:1' return after $current
109
+ -------------------- raw data ---------------------------------
110
+ 24.04.(11:12:58) INFO->Q: select from ex_names
111
+ <ex_names[#1:0]: age : 81, child : <ex_names[#2:1]: age : 58, child : < ex_names: #1:1 >, name : Alcaoa>, name : Guthorn>
112
+ <ex_names[#1:1]: age : 83, child : <ex_names[#4:0]: age : 20, child : < ex_names: #1:1 >, name : Tomasulo>, name : Gorby>
113
+ <ex_names[#2:0]: age : 16, child : <ex_names[#3:0]: age : 50, child : < ex_names: #1:0 >, name : Sniezek>, name : Fulkerson>
114
+ <ex_names[#2:1]: age : 58, child : <ex_names[#1:1]: age : 83, child : < ex_names: #4:0 >, name : Gorby>, name : Alcaoa>
115
+ <ex_names[#3:0]: age : 50, child : <ex_names[#1:0]: age : 81, child : < ex_names: #2:1 >, name : Guthorn>, name : Sniezek>
116
+ <ex_names[#4:0]: age : 20, child : <ex_names[#1:1]: age : 83, child : < ex_names: #4:0 >, name : Gorby>, name : Tomasulo>
117
+ <ex_names[#5:0]: age : 7, child : <ex_names[#2:1]: age : 58, child : < ex_names: #1:1 >, name : Alcaoa>, name : Portwine>
118
+ <ex_names[#6:0]: age : 57, child : <ex_names[#2:1]: age : 58, child : < ex_names: #1:1 >, name : Alcaoa>, name : Keala>
119
+ <ex_names[#7:0]: age : 31, child : <ex_names[#8:0]: age : 23, child : < ex_names: #6:0 >, name : Jacks>, name : Revelli>
120
+ <ex_names[#8:0]: age : 23, child : <ex_names[#6:0]: age : 57, child : < ex_names: #2:1 >, name : Keala>, name : Jacks>
121
+ --------------- Parent and Children ---------------------------
122
+ 24.04.(11:12:58) INFO->Q: select name, child.name from ex_names
123
+ {:name=>"Guthorn", :"child.name"=>"Alcaoa"}
124
+ {:name=>"Gorby", :"child.name"=>"Tomasulo"}
125
+ {:name=>"Fulkerson", :"child.name"=>"Sniezek"}
126
+ {:name=>"Alcaoa", :"child.name"=>"Gorby"}
127
+ {:name=>"Sniezek", :"child.name"=>"Guthorn"}
128
+ {:name=>"Tomasulo", :"child.name"=>"Gorby"}
129
+ {:name=>"Portwine", :"child.name"=>"Alcaoa"}
130
+ {:name=>"Keala", :"child.name"=>"Alcaoa"}
131
+ {:name=>"Revelli", :"child.name"=>"Jacks"}
132
+ {:name=>"Jacks", :"child.name"=>"Keala"}
133
+ --------------- unidirectional relation -----------------------
134
+ 24.04.(11:12:58) INFO->Q: select name as parent, age as parent_age, child.age, child.child.age as second_generation_age from ex_names order by parent_age
135
+ {:parent=>"Portwine", :parent_age=>7, :second_generation_age=>83, :"child.age"=>58}
136
+ {:parent=>"Fulkerson", :parent_age=>16, :second_generation_age=>81, :"child.age"=>50}
137
+ {:parent=>"Tomasulo", :parent_age=>20, :second_generation_age=>20, :"child.age"=>83}
138
+ {:parent=>"Jacks", :parent_age=>23, :second_generation_age=>58, :"child.age"=>57}
139
+ {:parent=>"Revelli", :parent_age=>31, :second_generation_age=>57, :"child.age"=>23}
140
+ {:parent=>"Sniezek", :parent_age=>50, :second_generation_age=>58, :"child.age"=>81}
141
+ {:parent=>"Keala", :parent_age=>57, :second_generation_age=>83, :"child.age"=>58}
142
+ {:parent=>"Alcaoa", :parent_age=>58, :second_generation_age=>20, :"child.age"=>83}
143
+ {:parent=>"Guthorn", :parent_age=>81, :second_generation_age=>83, :"child.age"=>58}
144
+ {:parent=>"Gorby", :parent_age=>83, :second_generation_age=>83, :"child.age"=>20}
145
+ ----------------- query relation - teenager -------------------
146
+ 24.04.(11:12:58) INFO->Q: select name as parent, child:{name, age} as teenager from ex_names where child.age between 10 and 25
147
+ {:parent=>"Gorby", :teenager=>{:name=>"Tomasulo", :age=>20}}
148
+ {:parent=>"Revelli", :teenager=>{:name=>"Jacks", :age=>23}}
149
+
@@ -0,0 +1,56 @@
1
+ ##
2
+ ## This example realises a 1:n relation using a `embedded`property
3
+ #
4
+ ## Its implemented in modelfiles located in spec/model
5
+ # and runs in the test environment.
6
+ ##
7
+ require 'bundler/setup'
8
+ require 'zeitwerk'
9
+ require 'arcade'
10
+
11
+ include Arcade
12
+ ## require modelfiles
13
+ loader = Zeitwerk::Loader.new
14
+ loader.push_dir ("#{__dir__}/../spec/model")
15
+ loader.setup
16
+
17
+ ## clear test database
18
+
19
+ databases = Arcade::Api.databases
20
+ if databases.include?(Arcade::Config.database[:test])
21
+ Arcade::Api.drop_database Arcade::Config.database[:test]
22
+ end
23
+ Arcade::Api.create_database Arcade::Config.database[:test]
24
+
25
+ ## Universal Database handle
26
+ DB = Arcade::Init.connect 'test'
27
+
28
+ ## ------------------------------------------------------ End Setup ------------------------------------- ##
29
+ ##
30
+ ## We are realising a self referencing relation
31
+ ## name --> children
32
+ #
33
+
34
+
35
+ Ex::NewNames.create_type # initialize the database
36
+ # spec/models/ex/new_names.rb
37
+ # Put same names into the database
38
+ table = %w( Guthorn Fulkerson Sniezek Tomasulo Portwine Keala Revelli Jacks Gorby Alcaoa ).map do | name |
39
+ Ex::NewNames.insert name: name, age: rand(99)
40
+ end
41
+ # Connect randomly
42
+ children = (0..6).map{ | i | table[-i].rid }
43
+ puts children
44
+ i = 0
45
+ table.each.with_index do | n, i |
46
+ n.update children: [ children[i] &.rid, table[ rand(10)+5] &.rid].compact
47
+ end
48
+
49
+ puts "-------------------- raw data ---------------------------"
50
+ puts Ex::NewNames.all false
51
+
52
+ puts "--------------- Parent and Children ---------------------"
53
+
54
+ children_query = Ex::NewNames.query projection: ['name as parent', 'children[age]']
55
+ puts children_query.query
56
+