og 0.13.0 → 0.14.0
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.
- data/CHANGELOG +114 -0
- data/INSTALL +22 -0
- data/README +1 -1
- data/Rakefile +2 -2
- data/doc/RELEASES +17 -1
- data/lib/og.rb +9 -3
- data/lib/og/adapter.rb +13 -2
- data/lib/og/adapters/mysql.rb +13 -7
- data/lib/og/adapters/oracle.rb +12 -9
- data/lib/og/adapters/psql.rb +9 -7
- data/lib/og/adapters/sqlite.rb +14 -7
- data/lib/og/connection.rb +26 -5
- data/lib/og/database.rb +33 -27
- data/lib/og/enchant.rb +28 -4
- data/lib/og/meta.rb +30 -5
- data/lib/og/mixins/list.rb +158 -0
- data/lib/og/mixins/tree.rb +228 -0
- data/lib/og/{mock.rb → testing/mock.rb} +0 -0
- data/test/og/mixins/tc_list.rb +104 -0
- data/test/og/mixins/tc_tree.rb +59 -0
- data/test/og/tc_automanage.rb +45 -0
- data/test/tc_og.rb +29 -0
- metadata +13 -5
@@ -0,0 +1,228 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: tree.rb 326 2005-03-28 11:07:17Z gmosx $
|
4
|
+
|
5
|
+
# NOT WORKING YET !!!
|
6
|
+
|
7
|
+
require 'glue/attribute'
|
8
|
+
|
9
|
+
module Og
|
10
|
+
|
11
|
+
# A useful encapsulation of the nested intervals pattern for
|
12
|
+
# hierarchical SQL queries. Slightly adapted from the original
|
13
|
+
# article (http://www.dbazine.com/tropashko4.shtml)
|
14
|
+
|
15
|
+
module TreeTraversal
|
16
|
+
|
17
|
+
# The default prefix for the tree traversal helpers.
|
18
|
+
|
19
|
+
cattr_accessor :prefix, 'tree'
|
20
|
+
|
21
|
+
def self.child(sum, n)
|
22
|
+
power = 2 ** n
|
23
|
+
|
24
|
+
return sum * power
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
__END__
|
33
|
+
|
34
|
+
def xcoord(numer, denom)
|
35
|
+
num = numer + 1
|
36
|
+
den = denom * 2
|
37
|
+
|
38
|
+
while (num / 2).floor == (num / 2)
|
39
|
+
num /= 2
|
40
|
+
den /= 2
|
41
|
+
end
|
42
|
+
|
43
|
+
return num, den
|
44
|
+
end
|
45
|
+
|
46
|
+
#--
|
47
|
+
# TODO: optimize this
|
48
|
+
#++
|
49
|
+
|
50
|
+
def ycoord(numer, denom)
|
51
|
+
num, den = xcoord(numer, denom)
|
52
|
+
|
53
|
+
while den < denom
|
54
|
+
num *= 2
|
55
|
+
den *= 2
|
56
|
+
end
|
57
|
+
|
58
|
+
num = numer - num
|
59
|
+
|
60
|
+
while (num / 2).floor == (num / 2)
|
61
|
+
num /= 2
|
62
|
+
den /= 2
|
63
|
+
end
|
64
|
+
|
65
|
+
return num, den
|
66
|
+
end
|
67
|
+
|
68
|
+
def parent(numer, denom)
|
69
|
+
return nil if numer == 3
|
70
|
+
|
71
|
+
num = (numer - 1) / 2
|
72
|
+
den = denom / 2
|
73
|
+
|
74
|
+
while ((num-1)/4).floor == ((num-1)/4)
|
75
|
+
num = (num + 1) / 2
|
76
|
+
den = den / 2
|
77
|
+
end
|
78
|
+
|
79
|
+
return num, den
|
80
|
+
end
|
81
|
+
|
82
|
+
def sibling(numer, denom)
|
83
|
+
return nil if numer == 3
|
84
|
+
|
85
|
+
num = (numer - 1) / 2
|
86
|
+
den = denom / 2
|
87
|
+
sib = 1
|
88
|
+
|
89
|
+
while ((num-1)/4).floor == ((num-1)/4)
|
90
|
+
return sib if num == 1 and den == 1
|
91
|
+
num = (num + 1) / 2
|
92
|
+
den /= 2
|
93
|
+
sib += 1
|
94
|
+
end
|
95
|
+
|
96
|
+
return sib
|
97
|
+
end
|
98
|
+
|
99
|
+
def child(numer, denom, n)
|
100
|
+
power = 2 ** n
|
101
|
+
|
102
|
+
num = (numer * power) + 3 - power
|
103
|
+
den = denom * power
|
104
|
+
|
105
|
+
return num, den
|
106
|
+
end
|
107
|
+
|
108
|
+
def path(numer, denom)
|
109
|
+
return '' if numer == nil
|
110
|
+
n, d = parent(numer, denom)
|
111
|
+
return "#{path(n, d)}.#{sibling(numer, denom)}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def encode(path)
|
115
|
+
num = den = 1
|
116
|
+
postfix = ".#{path}."
|
117
|
+
|
118
|
+
while postfix.length > 1
|
119
|
+
sibling, postfix = postfix.split('.', 2)
|
120
|
+
num, den = child(num, den, sibling.to_i)
|
121
|
+
end
|
122
|
+
|
123
|
+
return num, den
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
require 'og'
|
128
|
+
|
129
|
+
class Comment
|
130
|
+
property :path, String
|
131
|
+
property :x, :y, Float
|
132
|
+
|
133
|
+
def initialize(path = nil, x = nil, y = nil)
|
134
|
+
@path, @x, @y = path, x, y
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
Og::Database.new(
|
139
|
+
:database => 'test',
|
140
|
+
:adapter => 'psql',
|
141
|
+
:user => 'postgres',
|
142
|
+
:password => 'navelrulez',
|
143
|
+
:connection_count => 1,
|
144
|
+
:drop => true
|
145
|
+
)
|
146
|
+
|
147
|
+
def dp(path)
|
148
|
+
n, d = encode(path)
|
149
|
+
n, d = Float(n), Float(d)
|
150
|
+
# puts "#{path} -> n: #{n} d: #{d} c: #{n/d}"
|
151
|
+
p = path(n, d)
|
152
|
+
# puts "=== #{p}"
|
153
|
+
xn, xd = xcoord(n, d)
|
154
|
+
yn, yd = ycoord(n, d)
|
155
|
+
Comment.create(path, xn/xd, yn/yd)
|
156
|
+
end
|
157
|
+
|
158
|
+
dp '1.1'
|
159
|
+
dp '1.2'
|
160
|
+
dp '1.3'
|
161
|
+
dp '1.1.2.1'
|
162
|
+
dp '1.5.2.1'
|
163
|
+
dp '1.2.1.1.1'
|
164
|
+
dp '1.4.1.1'
|
165
|
+
dp '1.4.3'
|
166
|
+
dp '1.4.1'
|
167
|
+
dp '1.2.1'
|
168
|
+
dp '1.2.1.2'
|
169
|
+
dp '1.5'
|
170
|
+
dp '1.5.1'
|
171
|
+
|
172
|
+
for c in Comment.all('ORDER BY x DESC, y ASC')
|
173
|
+
puts "#{c.path.ljust(16)}#{c.inspect}"
|
174
|
+
end
|
175
|
+
|
176
|
+
class Article
|
177
|
+
property :title, :body, String
|
178
|
+
has_many: :comments, Comment, :tree => true
|
179
|
+
end
|
180
|
+
|
181
|
+
class Comment
|
182
|
+
property :body, String
|
183
|
+
belongs_to :article, Article
|
184
|
+
belongs_to :parent, Comment
|
185
|
+
has_many :children, Comment, :tree => true
|
186
|
+
has_many :roles, Role, :list => true
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
article.comments_tree
|
191
|
+
comment.add_child(Comment.new('hello'))
|
192
|
+
comment.children_tree
|
193
|
+
comment.children
|
194
|
+
|
195
|
+
if options[:tree]
|
196
|
+
code << %{
|
197
|
+
property :#{prefix}_x, Fixnum
|
198
|
+
property :#{prefix}_y, Fixnum
|
199
|
+
sql_index '#{prefix}_x, #{prefix}_y'
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
if options[:tree]
|
204
|
+
|
205
|
+
code << %{
|
206
|
+
def #{name}_tree(extrasql = nil)
|
207
|
+
Og.db.select("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\} ORDER BY #{prefix}_x DESC, #{prefix}_y ASC", #{klass})
|
208
|
+
end
|
209
|
+
}
|
210
|
+
|
211
|
+
elsif options[:list]
|
212
|
+
|
213
|
+
else
|
214
|
+
|
215
|
+
end
|
216
|
+
|
217
|
+
}
|
218
|
+
|
219
|
+
if options[:tree]
|
220
|
+
code << %{
|
221
|
+
n = Og.db.count("#{linkback}=\#\@oid", #{klass})
|
222
|
+
ptx = @#{prefix}_x || 0
|
223
|
+
pty = @#{prefix}_y || 0
|
224
|
+
obj.#{prefix}_x, obj.#{prefix}_y = TreeTraversal.child(ptx + pty, n)
|
225
|
+
}
|
226
|
+
end
|
227
|
+
|
228
|
+
code << %{
|
File without changes
|
@@ -0,0 +1,104 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'og'
|
7
|
+
|
8
|
+
$og = Og::Database.new(
|
9
|
+
:adapter => 'psql',
|
10
|
+
:database => 'test',
|
11
|
+
:user => 'postgres',
|
12
|
+
:password => 'navelrulez',
|
13
|
+
:drop => true
|
14
|
+
)
|
15
|
+
|
16
|
+
class TestCaseOgList < Test::Unit::TestCase # :nodoc: all
|
17
|
+
include N
|
18
|
+
|
19
|
+
class Comment; end
|
20
|
+
|
21
|
+
class Article
|
22
|
+
property :title, :body, String
|
23
|
+
has_many :comments, Comment, :list => true, :order => 'position DESC'
|
24
|
+
|
25
|
+
def initialize(title = nil)
|
26
|
+
@title = title
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Comment
|
31
|
+
property :body, String
|
32
|
+
belongs_to :article, Article
|
33
|
+
acts_as_list :scope => :article
|
34
|
+
|
35
|
+
def initialize(body = nil)
|
36
|
+
@body = body
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_all
|
41
|
+
$og.auto_manage_classes
|
42
|
+
|
43
|
+
a = Article.create('article')
|
44
|
+
a.save
|
45
|
+
|
46
|
+
c1 = Comment.new('1')
|
47
|
+
a.add_comment(c1)
|
48
|
+
c2 = Comment.new('2')
|
49
|
+
a.add_comment(c2)
|
50
|
+
c3 = Comment.new('3')
|
51
|
+
a.add_comment(c3)
|
52
|
+
|
53
|
+
assert_equal 1, c1.position
|
54
|
+
assert_equal 2, c2.position
|
55
|
+
assert_equal 3, c3.position
|
56
|
+
|
57
|
+
c3.move_higher
|
58
|
+
|
59
|
+
c1.reload
|
60
|
+
c2.reload
|
61
|
+
c3.reload
|
62
|
+
|
63
|
+
assert_equal 1, c1.position
|
64
|
+
assert_equal 2, c3.position
|
65
|
+
assert_equal 3, c2.position
|
66
|
+
|
67
|
+
c2.move_to_top
|
68
|
+
|
69
|
+
c1.reload
|
70
|
+
c2.reload
|
71
|
+
c3.reload
|
72
|
+
|
73
|
+
assert_equal 1, c2.position
|
74
|
+
assert_equal 2, c1.position
|
75
|
+
assert_equal 3, c3.position
|
76
|
+
|
77
|
+
c2.move_to_bottom
|
78
|
+
|
79
|
+
c1.reload
|
80
|
+
c2.reload
|
81
|
+
c3.reload
|
82
|
+
|
83
|
+
assert_equal 1, c1.position
|
84
|
+
assert_equal 2, c3.position
|
85
|
+
assert_equal 3, c2.position
|
86
|
+
|
87
|
+
c3.delete!
|
88
|
+
|
89
|
+
c1.reload
|
90
|
+
c2.reload
|
91
|
+
|
92
|
+
assert_equal 1, c1.position
|
93
|
+
assert_equal 2, c2.position
|
94
|
+
|
95
|
+
c2.delete!
|
96
|
+
|
97
|
+
c1.reload
|
98
|
+
|
99
|
+
assert_equal 1, c1.position
|
100
|
+
|
101
|
+
c1.delete!
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'og'
|
7
|
+
|
8
|
+
$og = Og::Database.new(
|
9
|
+
:adapter => 'psql',
|
10
|
+
:database => 'test',
|
11
|
+
:user => 'postgres',
|
12
|
+
:password => 'navelrulez',
|
13
|
+
:drop => true
|
14
|
+
)
|
15
|
+
|
16
|
+
class TestCaseOgTree < Test::Unit::TestCase # :nodoc: all
|
17
|
+
include N
|
18
|
+
|
19
|
+
class Comment; end
|
20
|
+
|
21
|
+
class Article
|
22
|
+
property :title, :body, String
|
23
|
+
has_many :comments, Comment, :tree => true
|
24
|
+
|
25
|
+
def initialize(title = nil)
|
26
|
+
@title = title
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Comment
|
31
|
+
property :body, String
|
32
|
+
belongs_to :article, Article
|
33
|
+
belongs_to :comment, Comment
|
34
|
+
has_many :comments, Comment, :tree => true
|
35
|
+
|
36
|
+
def initialize(body = nil)
|
37
|
+
@body = body
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_all
|
42
|
+
$og.auto_manage_classes
|
43
|
+
|
44
|
+
a = Article.new('article')
|
45
|
+
a.save
|
46
|
+
|
47
|
+
c1 = Comment.new('1')
|
48
|
+
a.add_comment(c1)
|
49
|
+
c11 = Comment.new('1.1')
|
50
|
+
c1.add_comment(c11)
|
51
|
+
c1.save
|
52
|
+
|
53
|
+
puts "\n\n"
|
54
|
+
a.comments_tree.each do |c|
|
55
|
+
puts "#{c.body.ljust(16)}[#{c.tree_x},#{c.tree_y}]"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'og'
|
7
|
+
|
8
|
+
$og = Og::Database.new(
|
9
|
+
:adapter => 'psql',
|
10
|
+
:database => 'test',
|
11
|
+
:user => 'postgres',
|
12
|
+
:password => 'navelrulez',
|
13
|
+
:drop => true
|
14
|
+
)
|
15
|
+
|
16
|
+
class TestCaseOgObserver < Test::Unit::TestCase # :nodoc: all
|
17
|
+
include N
|
18
|
+
|
19
|
+
# Define a class after the Database is created.
|
20
|
+
|
21
|
+
class User
|
22
|
+
property :name
|
23
|
+
|
24
|
+
# auto forward ref.
|
25
|
+
has_many :articles, TestCaseOgObserver::Article
|
26
|
+
end
|
27
|
+
|
28
|
+
class Article
|
29
|
+
property :name, String
|
30
|
+
property :age, Fixnum
|
31
|
+
|
32
|
+
def initialize (name = nil, age = nil)
|
33
|
+
@name, @age = name, age
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_all
|
38
|
+
assert_equal 0, $og.managed_classes.size
|
39
|
+
$og.auto_manage_classes
|
40
|
+
assert_equal 2, $og.managed_classes.size
|
41
|
+
assert $og.managed_classes.include?(User)
|
42
|
+
assert $og.managed_classes.include?(Article)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/test/tc_og.rb
CHANGED
@@ -336,6 +336,35 @@ class TC_N_OG < Test::Unit::TestCase
|
|
336
336
|
|
337
337
|
# not saved due to not nul constraint.
|
338
338
|
assert_equal nil, role
|
339
|
+
|
340
|
+
# test reload.
|
341
|
+
|
342
|
+
User.create('karras')
|
343
|
+
|
344
|
+
u1 = User['karras']
|
345
|
+
u2 = User['karras']
|
346
|
+
|
347
|
+
u1.name = 'vaio'
|
348
|
+
u1.save
|
349
|
+
|
350
|
+
assert_equal 'vaio', u1.name
|
351
|
+
assert_equal 'karras', u2.name
|
352
|
+
|
353
|
+
u2.reload!
|
354
|
+
|
355
|
+
assert_equal 'vaio', u2.name
|
356
|
+
|
357
|
+
# test raise db exception.
|
358
|
+
|
359
|
+
assert_raises(Og::SqlException) {
|
360
|
+
User.select('SEGECT *')
|
361
|
+
}
|
362
|
+
|
363
|
+
Og.raise_db_exceptions = false
|
364
|
+
|
365
|
+
assert_nothing_raised {
|
366
|
+
User.select('SEGECT *')
|
367
|
+
}
|
339
368
|
|
340
369
|
og.put_connection
|
341
370
|
og.shutdown
|