vagas-orientdb4r 0.5.2
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/.coveralls.yml +1 -0
- data/.gitignore +26 -0
- data/.travis.yml +18 -0
- data/Gemfile +9 -0
- data/LICENSE +202 -0
- data/README.rdoc +124 -0
- data/Rakefile +43 -0
- data/changelog.txt +60 -0
- data/ci/initialize-ci.sh +36 -0
- data/fstudy/design_v1.dia +0 -0
- data/fstudy/design_v1.png +0 -0
- data/fstudy/domain_model.dia +0 -0
- data/fstudy/domain_model.png +0 -0
- data/fstudy/flat_class_perf.rb +56 -0
- data/fstudy/sample1_object_diagram.dia +0 -0
- data/fstudy/sample1_object_diagram.png +0 -0
- data/fstudy/study_case.rb +87 -0
- data/fstudy/technical_feasibility.rb +256 -0
- data/lib/orientdb4r.rb +115 -0
- data/lib/orientdb4r/bin/client.rb +86 -0
- data/lib/orientdb4r/bin/connection.rb +29 -0
- data/lib/orientdb4r/bin/constants.rb +20 -0
- data/lib/orientdb4r/bin/io.rb +38 -0
- data/lib/orientdb4r/bin/protocol28.rb +101 -0
- data/lib/orientdb4r/bin/protocol_factory.rb +25 -0
- data/lib/orientdb4r/chained_error.rb +37 -0
- data/lib/orientdb4r/client.rb +364 -0
- data/lib/orientdb4r/load_balancing.rb +113 -0
- data/lib/orientdb4r/node.rb +42 -0
- data/lib/orientdb4r/rest/client.rb +517 -0
- data/lib/orientdb4r/rest/excon_node.rb +115 -0
- data/lib/orientdb4r/rest/model.rb +159 -0
- data/lib/orientdb4r/rest/node.rb +43 -0
- data/lib/orientdb4r/rest/restclient_node.rb +77 -0
- data/lib/orientdb4r/rid.rb +54 -0
- data/lib/orientdb4r/utils.rb +203 -0
- data/lib/orientdb4r/version.rb +39 -0
- data/orientdb4r.gemspec +37 -0
- data/test/bin/test_client.rb +21 -0
- data/test/readme_sample.rb +38 -0
- data/test/test_client.rb +93 -0
- data/test/test_database.rb +261 -0
- data/test/test_ddo.rb +237 -0
- data/test/test_dmo.rb +115 -0
- data/test/test_document_crud.rb +184 -0
- data/test/test_gremlin.rb +52 -0
- data/test/test_helper.rb +10 -0
- data/test/test_loadbalancing.rb +81 -0
- data/test/test_utils.rb +67 -0
- metadata +136 -0
data/ci/initialize-ci.sh
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
PARENT_DIR=$(dirname $(cd "$(dirname "$0")"; pwd))
|
|
4
|
+
CI_DIR="$PARENT_DIR/ci/environment"
|
|
5
|
+
#CI_DIR=/tmp/travis
|
|
6
|
+
|
|
7
|
+
ODB_VERSION=${1:-"2.0.4"}
|
|
8
|
+
ODB_DIR="${CI_DIR}/orientdb-community-${ODB_VERSION}"
|
|
9
|
+
ODB_LAUNCHER="${ODB_DIR}/bin/server.sh"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
echo "=== Initializing CI environment ==="
|
|
14
|
+
cd "$PARENT_DIR"
|
|
15
|
+
mkdir -p $CI_DIR
|
|
16
|
+
|
|
17
|
+
echo "--- Downloading OrientDB v${ODB_VERSION} ---"
|
|
18
|
+
wget -q -O "$CI_DIR/orientdb-community-${ODB_VERSION}.tar.gz" "http://www.orientechnologies.com/download.php?email=unknown@unknown.com&file=orientdb-community-${ODB_VERSION}.tar.gz&os=linux"
|
|
19
|
+
|
|
20
|
+
echo "--- Unpacking ---------------------"
|
|
21
|
+
tar xf $CI_DIR/orientdb-community-${ODB_VERSION}.tar.gz -C $CI_DIR
|
|
22
|
+
|
|
23
|
+
echo "--- Setting up --------------------"
|
|
24
|
+
chmod +x $ODB_LAUNCHER
|
|
25
|
+
chmod -R +rw "${ODB_DIR}/config/"
|
|
26
|
+
ODB_ADMIN="<users><user resources=\"*\" password=\"root\" name=\"root\"/></users>"
|
|
27
|
+
sed "s:^[ \t]*<users.*$: $ODB_ADMIN:" -i ${ODB_DIR}/config/orientdb-server-config.xml
|
|
28
|
+
sed "s:^[ \t]*<\/users.*$: <!-- \/users -->:" -i ${ODB_DIR}/config/orientdb-server-config.xml
|
|
29
|
+
sed "s:^handlers = .*$:handlers = java.util.logging.ConsoleHandler:" -i ${ODB_DIR}/config/orientdb-server-log.properties
|
|
30
|
+
|
|
31
|
+
echo "--- Starting server ---------------"
|
|
32
|
+
sh -c $ODB_LAUNCHER </dev/null &>/dev/null &
|
|
33
|
+
|
|
34
|
+
# Wait a bit for OrientDB to finish the initialization phase.
|
|
35
|
+
sleep 5
|
|
36
|
+
printf "=== The CI environment has been initialized ===\n"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'study_case'
|
|
2
|
+
|
|
3
|
+
# This class tests performance on a simple flat class.
|
|
4
|
+
class FlatClassPerf < FStudy::Case
|
|
5
|
+
|
|
6
|
+
def db; 'perf'; end
|
|
7
|
+
|
|
8
|
+
def drop
|
|
9
|
+
client.drop_class 'User'
|
|
10
|
+
end
|
|
11
|
+
def model
|
|
12
|
+
drop
|
|
13
|
+
client.create_class 'User' do |c|
|
|
14
|
+
c.property 'username', :string, :mandatory => true
|
|
15
|
+
c.property 'name', :string, :mandatory => true
|
|
16
|
+
c.property 'admin', :boolean
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
def del
|
|
20
|
+
client.command 'DELETE FROM User'
|
|
21
|
+
end
|
|
22
|
+
def data
|
|
23
|
+
1.upto(100000) do |i|
|
|
24
|
+
Orientdb4r::logger.info "...done: #{i}" if 0 == (i % 1000)
|
|
25
|
+
first_name = dg.word
|
|
26
|
+
surname = dg.word
|
|
27
|
+
begin
|
|
28
|
+
client.create_document({ '@class' => 'User', \
|
|
29
|
+
:username => "#{first_name}.#{surname}", \
|
|
30
|
+
:name => "#{first_name.capitalize} #{surname.capitalize}", \
|
|
31
|
+
:admin => (0 == rand(2)) })
|
|
32
|
+
rescue Exception => e
|
|
33
|
+
Orientdb4r::logger.error e
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def product
|
|
39
|
+
1.upto(500000) do |i|
|
|
40
|
+
Orientdb4r::logger.info "...done: #{i}" if 0 == (i % 100000)
|
|
41
|
+
name = dg.word
|
|
42
|
+
type = (rand(3) == 0) ? 'a' : 'b'
|
|
43
|
+
begin
|
|
44
|
+
client.command "insert into product cluster #{type} (name,type) values ('#{name}','#{type}')"
|
|
45
|
+
# client.command "insert into product_simple (name,type) values ('#{name}','#{type}')"
|
|
46
|
+
rescue Exception => e
|
|
47
|
+
Orientdb4r::logger.error e
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
c = FlatClassPerf.new
|
|
55
|
+
c.run
|
|
56
|
+
puts 'OK'
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'orientdb4r'
|
|
2
|
+
|
|
3
|
+
module FStudy
|
|
4
|
+
|
|
5
|
+
###
|
|
6
|
+
# This class represents a elaboration infrastructure.
|
|
7
|
+
class Case
|
|
8
|
+
|
|
9
|
+
attr_reader :dg
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@dg = DataGenerator.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def db
|
|
16
|
+
'temp' # default DB is 'temp'
|
|
17
|
+
end
|
|
18
|
+
def host
|
|
19
|
+
'localhost'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def client
|
|
23
|
+
Orientdb4r.client :host => host
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def watch method
|
|
27
|
+
start = Time.now
|
|
28
|
+
self.send method.to_sym
|
|
29
|
+
Orientdb4r::logger.info "method '#{method}' performed in #{Time.now - start} [s]"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def run
|
|
33
|
+
threads = []
|
|
34
|
+
thread_cnt = 1
|
|
35
|
+
thc = ARGV.select { |arg| arg if arg =~ /-th=\d+/ }
|
|
36
|
+
thread_cnt = thc[0][4..-1].to_i unless thc.empty?
|
|
37
|
+
|
|
38
|
+
if thread_cnt > 1
|
|
39
|
+
1.upto(thread_cnt) do
|
|
40
|
+
threads << Thread.new do
|
|
41
|
+
run_threaded
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
run_threaded
|
|
46
|
+
end
|
|
47
|
+
threads.each { |th| th.join }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def run_threaded
|
|
54
|
+
Orientdb4r::logger.info "started thread #{Thread.current}"
|
|
55
|
+
client.connect :database => db, :user => 'admin', :password => 'admin'
|
|
56
|
+
ARGV.each do |arg|
|
|
57
|
+
watch arg[2..-1].to_sym if arg =~ /^--\w/
|
|
58
|
+
end
|
|
59
|
+
client.disconnect
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class DataGenerator
|
|
66
|
+
|
|
67
|
+
def initialize
|
|
68
|
+
@words = IO.readlines('/usr/share/dict/words')
|
|
69
|
+
0.upto(@words.size - 1) do |i|
|
|
70
|
+
word = @words[i]
|
|
71
|
+
word.strip!.downcase!
|
|
72
|
+
idx = word.index("'")
|
|
73
|
+
word = word[0..(idx - 1)] unless idx.nil?
|
|
74
|
+
@words[i] = word
|
|
75
|
+
end
|
|
76
|
+
@words.uniq!
|
|
77
|
+
Orientdb4r::logger.info "DataGenerator: #{@words.size} words"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Gets a random word.
|
|
81
|
+
def word
|
|
82
|
+
@words[rand(@words.size)]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
require 'study_case'
|
|
2
|
+
|
|
3
|
+
# This class represents model and data for Technical Feasibility Study.
|
|
4
|
+
# See here for more info:
|
|
5
|
+
# https://github.com/veny/orientdb4r/wiki/Technical-Feasibility
|
|
6
|
+
class TechnicalFeasibility < FStudy::Case
|
|
7
|
+
|
|
8
|
+
def db; 'perf'; end
|
|
9
|
+
|
|
10
|
+
# Dropes the document model.
|
|
11
|
+
def drop
|
|
12
|
+
classes_definition.reverse.each do |clazz|
|
|
13
|
+
client.drop_class clazz[:class]
|
|
14
|
+
puts "droped class: #{clazz[:class]}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Creates the document model.
|
|
19
|
+
def model
|
|
20
|
+
drop
|
|
21
|
+
classes_definition.each do |clazz|
|
|
22
|
+
class_name = clazz.delete :class
|
|
23
|
+
client.create_class(class_name, clazz)
|
|
24
|
+
puts "created class: #{class_name}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Deletes data.
|
|
29
|
+
def del
|
|
30
|
+
classes_definition.each do |clazz|
|
|
31
|
+
client.command "DELETE FROM #{clazz[:class]}"
|
|
32
|
+
puts "deleted from class: #{clazz[:class]}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Prepares data.
|
|
37
|
+
def data
|
|
38
|
+
communities = insert_communities
|
|
39
|
+
units = insert_org_units
|
|
40
|
+
users = insert_users(10000, units, communities)
|
|
41
|
+
insert_contacts(users, 7) # max pro user => ~ coeficient 4.0 pro user
|
|
42
|
+
contents = insert_contents(users, communities, 1.0) # coeficient pro user
|
|
43
|
+
insert_activities(users, communities, contents, 100) # coeficient pro user
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def count
|
|
47
|
+
puts client.query 'SELECT count(*) FROM User'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def insert_communities
|
|
54
|
+
communities = [
|
|
55
|
+
{ :name => 'Pianists' },
|
|
56
|
+
{ :name => 'Violinists' },
|
|
57
|
+
{ :name => 'Dog fanciers' },
|
|
58
|
+
{ :name => 'Cat fanciers' },
|
|
59
|
+
{ :name => 'Soccer fans' },
|
|
60
|
+
{ :name => 'Ski fans' },
|
|
61
|
+
{ :name => 'Basket fans' },
|
|
62
|
+
{ :name => 'Gourmets' },
|
|
63
|
+
{ :name => 'Scifi reader' },
|
|
64
|
+
{ :name => 'Comic reader' }
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
start = Time.now
|
|
68
|
+
communities.each do |c|
|
|
69
|
+
c['@class'] = 'Community'
|
|
70
|
+
c[:rid] = client.create_document(c)
|
|
71
|
+
end
|
|
72
|
+
puts "Created Communities: #{communities.size}, time = #{Time.now - start} [s]"
|
|
73
|
+
communities
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def insert_org_units
|
|
77
|
+
units = [
|
|
78
|
+
{ :name => 'BigCompany', :descendants => [ 'Automotive', 'Research', 'Infrastructure' ] },
|
|
79
|
+
{ :name => 'Automotive', :descendants => [ 'Sales', 'Marketing', 'Design' ] },
|
|
80
|
+
{ :name => 'Sales' },
|
|
81
|
+
{ :name => 'Marketing' },
|
|
82
|
+
{ :name => 'Design' },
|
|
83
|
+
{ :name => 'Research', :descendants => [ 'Scientist', 'Spies' ] },
|
|
84
|
+
{ :name => 'Scientist' },
|
|
85
|
+
{ :name => 'Spies' },
|
|
86
|
+
{ :name => 'Infrastructure', :descendants => [ 'Accounting', 'HumanResources' ] },
|
|
87
|
+
{ :name => 'Accounting' },
|
|
88
|
+
{ :name => 'HumanResources' , :descendants => [ 'Recruitment' ] },
|
|
89
|
+
{ :name => 'Recruitment' }
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
start = Time.now
|
|
93
|
+
units.each { |unit| insert_org_unit_helper(unit, units) }
|
|
94
|
+
puts "Created OrgUnits: #{units.size}, time = #{Time.now - start} [s]"
|
|
95
|
+
units
|
|
96
|
+
end
|
|
97
|
+
def insert_org_unit_helper(unit, all)
|
|
98
|
+
return if unit.include? :rid
|
|
99
|
+
|
|
100
|
+
if unit.include? :descendants
|
|
101
|
+
# recursion
|
|
102
|
+
unit[:descendants].each do |desc_name|
|
|
103
|
+
next_unit = all.select { |u| u if u[:name] == desc_name }[0]
|
|
104
|
+
insert_org_unit_helper(next_unit, all) unless next_unit.include? :rid
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
cloned = unit.clone
|
|
109
|
+
cloned['@class'] = 'OrgUnit'
|
|
110
|
+
cloned.delete :descendants
|
|
111
|
+
|
|
112
|
+
if unit.include? :descendants
|
|
113
|
+
descendants = []
|
|
114
|
+
unit[:descendants].each do |name|
|
|
115
|
+
descendants << all.select { |ou| ou if ou[:name] == name }[0][:rid]
|
|
116
|
+
end
|
|
117
|
+
cloned[:descendants] = descendants
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
rid = client.create_document(cloned)
|
|
121
|
+
unit[:rid] = rid
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def insert_users(count, units, communities)
|
|
125
|
+
start = Time.now
|
|
126
|
+
users = []
|
|
127
|
+
1.upto(count) do
|
|
128
|
+
firstname = dg.word
|
|
129
|
+
surname = dg.word
|
|
130
|
+
username = "#{firstname}.#{surname}"
|
|
131
|
+
# random distribution of Units (1) & Communities (0..3)
|
|
132
|
+
unit = units[rand(units.size)]
|
|
133
|
+
comms = []
|
|
134
|
+
0.upto(rand(4)) { |i| comms << communities[rand(communities.size)][:rid] if i > 0 }
|
|
135
|
+
|
|
136
|
+
user = { '@class' => 'User', \
|
|
137
|
+
:username => username, \
|
|
138
|
+
:firstname => firstname.capitalize, \
|
|
139
|
+
:surname => surname.capitalize, \
|
|
140
|
+
:unit => unit[:rid], \
|
|
141
|
+
:communities => comms }
|
|
142
|
+
rid = client.create_document(user)
|
|
143
|
+
user[:rid] = rid
|
|
144
|
+
users << user
|
|
145
|
+
end
|
|
146
|
+
puts "Created Users: #{users.size}, time = #{Time.now - start} [s]"
|
|
147
|
+
users
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def insert_contacts(users, max_contacts)
|
|
151
|
+
start = Time.now
|
|
152
|
+
count = 0
|
|
153
|
+
types = [:friend, :family, :coworker, :enemy]
|
|
154
|
+
0.upto(users.size - 1) do |i|
|
|
155
|
+
a = users[i]
|
|
156
|
+
0.upto(rand(max_contacts)) do
|
|
157
|
+
b = users[rand(users.size)]
|
|
158
|
+
client.create_document({'@class' => 'Contact', :a => a[:rid], :b => b[:rid], :type => rand(types.size)})
|
|
159
|
+
count += 1
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
puts "Created Contacts: #{count}, time = #{Time.now - start} [s]"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def insert_contents(users, communities, user_coef = 1.0)
|
|
166
|
+
start = Time.now
|
|
167
|
+
contents = []
|
|
168
|
+
classes = [['Article', 'body'], ['Gallery', 'description'], ['Term', 'topic']]
|
|
169
|
+
limit = (users.size * user_coef).to_i
|
|
170
|
+
|
|
171
|
+
1.upto(limit) do
|
|
172
|
+
clazz = classes[rand(classes.size)]
|
|
173
|
+
content = {'@class' => clazz[0], :title => "#{dg.word} #{dg.word}", clazz[1] => dg.word}
|
|
174
|
+
# random distribution of Users (1) & Communities (0..3)
|
|
175
|
+
content[:author] = users[rand(users.size)][:rid]
|
|
176
|
+
comms = []
|
|
177
|
+
0.upto(rand(4)) { |i| comms << communities[rand(communities.size)][:rid] if i > 0 }
|
|
178
|
+
content[:communities] = comms
|
|
179
|
+
|
|
180
|
+
rid = client.create_document(content)
|
|
181
|
+
content[:rid] = rid
|
|
182
|
+
contents << content
|
|
183
|
+
end
|
|
184
|
+
puts "Created ContentTypes: #{contents.size}, time = #{Time.now - start} [s]"
|
|
185
|
+
contents
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def insert_activities(users, communities, contents, user_coef)
|
|
189
|
+
start = Time.now
|
|
190
|
+
types = [:login, :logout, :likeit, :rated, :saw, :commented]
|
|
191
|
+
limit = users.size * user_coef
|
|
192
|
+
1.upto(limit) do |i|
|
|
193
|
+
puts "... #{i} #{Time.now - start}" if 0 == i % 100000
|
|
194
|
+
type = rand(types.size)
|
|
195
|
+
activity = { '@class' => 'Activity', :type => type, :stamp => (Time.now.to_i - rand(3600*23*30)) }
|
|
196
|
+
# random distribution of Users (1) & the same communities as user
|
|
197
|
+
user = users[rand(users.size)]
|
|
198
|
+
activity[:source] = user[:rid]
|
|
199
|
+
activity[:communities] = user[:communities]
|
|
200
|
+
# content
|
|
201
|
+
content = (types[type] == :login or types[type] == :logout) ? nil : contents[rand(contents.size)]
|
|
202
|
+
activity[content['@class'].downcase] = content[:rid] unless content.nil?
|
|
203
|
+
|
|
204
|
+
begin
|
|
205
|
+
client.create_document(activity)
|
|
206
|
+
rescue Exception => e
|
|
207
|
+
Orientdb4r::logger.error "problem storing index=#{i}, user=#{user.inspect}"
|
|
208
|
+
Orientdb4r::logger.error e
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
puts "Created Activities: #{limit}, time = #{Time.now - start} [s]"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def classes_definition
|
|
215
|
+
# TODO rdbms_id
|
|
216
|
+
[
|
|
217
|
+
{ :class => 'OrgUnit', :properties => [
|
|
218
|
+
{ :property => 'name', :type => :string, :mandatory => true },
|
|
219
|
+
# TODO domain
|
|
220
|
+
{ :property => 'descendants', :type => :linkset, :linked_class => 'OrgUnit' }]},
|
|
221
|
+
{ :class => 'Community', :properties => [
|
|
222
|
+
{ :property => 'name', :type => :string, :mandatory => true }]},
|
|
223
|
+
{ :class => 'User', :properties => [
|
|
224
|
+
{ :property => 'username', :type => :string, :mandatory => true },
|
|
225
|
+
{ :property => 'firstname', :type => :string, :mandatory => true },
|
|
226
|
+
{ :property => 'surname', :type => :string, :mandatory => true },
|
|
227
|
+
# TODO roles
|
|
228
|
+
{ :property => 'unit', :type => :link, :linked_class => 'OrgUnit', :mandatory => true },
|
|
229
|
+
{ :property => 'communities', :type => :linkset, :linked_class => 'Community' }]},
|
|
230
|
+
{ :class => 'Contact', :properties => [
|
|
231
|
+
{ :property => 'type', :type => :integer, :mandatory => true },
|
|
232
|
+
{ :property => 'a', :type => :link, :linked_class => 'User', :mandatory => true },
|
|
233
|
+
{ :property => 'b', :type => :link, :linked_class => 'User', :mandatory => true }]},
|
|
234
|
+
{ :class => 'Content', :properties => [
|
|
235
|
+
{ :property => 'title', :type => :string, :mandatory => true },
|
|
236
|
+
{ :property => 'author', :type => :link, :linked_class => 'User', :mandatory => true },
|
|
237
|
+
{ :property => 'accessible_in', :type => :linkset, :linked_class => 'Community' }]},
|
|
238
|
+
{ :class => 'Article', :extends => 'Content', :properties => [
|
|
239
|
+
{ :property => 'body', :type => :string, :mandatory => true }]},
|
|
240
|
+
{ :class => 'Gallery', :extends => 'Content', :properties => [
|
|
241
|
+
{ :property => 'description', :type => :string, :mandatory => true }]},
|
|
242
|
+
{ :class => 'Term', :extends => 'Content', :properties => [
|
|
243
|
+
{ :property => 'topic', :type => :string, :mandatory => true }]},
|
|
244
|
+
{ :class => 'Activity', :properties => [
|
|
245
|
+
{ :property => 'type', :type => :integer, :mandatory => true },
|
|
246
|
+
{ :property => 'stamp', :type => :integer, :mandatory => true },
|
|
247
|
+
{ :property => 'source', :type => :link, :linked_class => 'User', :mandatory => true },
|
|
248
|
+
{ :property => 'communities', :type => :linkset, :linked_class => 'Community' }]}
|
|
249
|
+
]
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
c = TechnicalFeasibility.new
|
|
255
|
+
c.run
|
|
256
|
+
puts 'OK'
|