og 0.16.0 → 0.17.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.
Files changed (69) hide show
  1. data/CHANGELOG +485 -0
  2. data/README +35 -12
  3. data/Rakefile +4 -7
  4. data/benchmark/bench.rb +1 -1
  5. data/doc/AUTHORS +3 -3
  6. data/doc/RELEASES +153 -2
  7. data/doc/config.txt +0 -7
  8. data/doc/tutorial.txt +7 -0
  9. data/examples/README +5 -0
  10. data/examples/mysql_to_psql.rb +25 -50
  11. data/examples/run.rb +62 -77
  12. data/install.rb +1 -1
  13. data/lib/og.rb +45 -106
  14. data/lib/og/collection.rb +156 -0
  15. data/lib/og/entity.rb +131 -0
  16. data/lib/og/errors.rb +10 -15
  17. data/lib/og/manager.rb +115 -0
  18. data/lib/og/{mixins → mixin}/hierarchical.rb +43 -37
  19. data/lib/og/{mixins → mixin}/orderable.rb +35 -35
  20. data/lib/og/{mixins → mixin}/timestamped.rb +0 -6
  21. data/lib/og/{mixins → mixin}/tree.rb +0 -4
  22. data/lib/og/relation.rb +178 -0
  23. data/lib/og/relation/belongs_to.rb +14 -0
  24. data/lib/og/relation/has_many.rb +62 -0
  25. data/lib/og/relation/has_one.rb +17 -0
  26. data/lib/og/relation/joins_many.rb +69 -0
  27. data/lib/og/relation/many_to_many.rb +17 -0
  28. data/lib/og/relation/refers_to.rb +31 -0
  29. data/lib/og/store.rb +223 -0
  30. data/lib/og/store/filesys.rb +113 -0
  31. data/lib/og/store/madeleine.rb +4 -0
  32. data/lib/og/store/memory.rb +291 -0
  33. data/lib/og/store/mysql.rb +283 -0
  34. data/lib/og/store/psql.rb +238 -0
  35. data/lib/og/store/sql.rb +599 -0
  36. data/lib/og/store/sqlite.rb +190 -0
  37. data/lib/og/store/sqlserver.rb +262 -0
  38. data/lib/og/types.rb +19 -0
  39. data/lib/og/validation.rb +0 -4
  40. data/test/og/{mixins → mixin}/tc_hierarchical.rb +21 -23
  41. data/test/og/{mixins → mixin}/tc_orderable.rb +15 -14
  42. data/test/og/mixin/tc_timestamped.rb +38 -0
  43. data/test/og/store/tc_filesys.rb +71 -0
  44. data/test/og/tc_relation.rb +36 -0
  45. data/test/og/tc_store.rb +290 -0
  46. data/test/og/tc_types.rb +21 -0
  47. metadata +54 -40
  48. data/examples/mock_example.rb +0 -50
  49. data/lib/og/adapters/base.rb +0 -706
  50. data/lib/og/adapters/filesys.rb +0 -117
  51. data/lib/og/adapters/mysql.rb +0 -350
  52. data/lib/og/adapters/oracle.rb +0 -368
  53. data/lib/og/adapters/psql.rb +0 -272
  54. data/lib/og/adapters/sqlite.rb +0 -265
  55. data/lib/og/adapters/sqlserver.rb +0 -356
  56. data/lib/og/database.rb +0 -290
  57. data/lib/og/enchant.rb +0 -149
  58. data/lib/og/meta.rb +0 -407
  59. data/lib/og/testing/mock.rb +0 -165
  60. data/lib/og/typemacros.rb +0 -24
  61. data/test/og/adapters/tc_filesys.rb +0 -83
  62. data/test/og/adapters/tc_sqlite.rb +0 -86
  63. data/test/og/adapters/tc_sqlserver.rb +0 -96
  64. data/test/og/tc_automanage.rb +0 -46
  65. data/test/og/tc_lifecycle.rb +0 -105
  66. data/test/og/tc_many_to_many.rb +0 -61
  67. data/test/og/tc_meta.rb +0 -55
  68. data/test/og/tc_validation.rb +0 -89
  69. data/test/tc_og.rb +0 -364
data/lib/og/types.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Og
2
+
3
+ # Some useful type macros to help when defining properties.
4
+ # You can easily code your own type macros. Just return the
5
+ # array that should be passed to the property macro.
6
+ #
7
+ # === Example
8
+ #
9
+ # property :name, VarChar(30)
10
+
11
+ def self.VarChar(size)
12
+ return String, :sql => "VARCHAR(#{size})"
13
+ end
14
+
15
+ NotNull = { :sql => 'NOT NULL' }.freeze
16
+
17
+ Null = { :sql => 'NULL' }.freeze
18
+
19
+ end
data/lib/og/validation.rb CHANGED
@@ -1,7 +1,3 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: validation.rb 1 2005-04-11 11:04:30Z gmosx $
4
-
5
1
  require 'glue/validation'
6
2
 
7
3
  module Glue
@@ -3,19 +3,18 @@ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
3
3
  require 'test/unit'
4
4
  require 'ostruct'
5
5
 
6
- require 'og/mixins/hierarchical'
7
-
8
6
  require 'og'
7
+ require 'og/mixin/hierarchical'
9
8
 
10
- $og = Og::Database.new(
11
- :adapter => 'psql',
12
- :database => 'test',
9
+ $og = Og.setup(
10
+ :store => 'psql',
11
+ :name => 'test',
13
12
  :user => 'postgres',
14
13
  :password => 'navelrulez',
15
- :drop => true
14
+ :destroy => true
16
15
  )
17
16
 
18
- class TestCaseOgHierarchical < Test::Unit::TestCase # :nodoc: all
17
+ class TC_OgHierarchical < Test::Unit::TestCase # :nodoc: all
19
18
 
20
19
  class Comment
21
20
  property :body, String
@@ -34,41 +33,40 @@ class TestCaseOgHierarchical < Test::Unit::TestCase # :nodoc: all
34
33
  end
35
34
 
36
35
  def test_all
37
- $og.auto_manage_classes
36
+ $og.manage_classes
38
37
 
39
38
  root = Comment.create('root')
40
39
  c1 = Comment.new('1')
41
- root.add_comment(c1)
40
+ root.add_comment c1
42
41
  c2 = Comment.new('1.1')
43
- c1.add_comment(c2)
42
+ c1.add_comment c2
44
43
  c3 = Comment.new('1.2')
45
- c1.add_comment(c3)
44
+ c1.add_comment c3
46
45
  c4 = Comment.new('1.1.1')
47
- c2.add_comment(c4)
46
+ c2.add_comment c4
48
47
  c5 = Comment.new('1.2.1')
49
- c3.add_comment(c5)
48
+ c3.add_comment c5
50
49
  c6 = Comment.new('1.1.1.1')
51
- c4.add_comment(c6)
50
+ c4.add_comment c6
52
51
  c7 = Comment.new('2')
53
- root.add_comment(c7)
52
+ root.add_comment c7
54
53
  c8 = Comment.new('3')
55
- root.add_comment(c8)
54
+ root.add_comment c8
56
55
  c9 = Comment.new('2.1')
57
- c7.add_comment(c9)
56
+ c7.add_comment c9
58
57
 
59
58
  c1.reload
60
- =begin
61
- Comment.all("ORDER BY lft, rgt").each { |c|
59
+
60
+ Comment.all(:order => "lft, rgt").each { |c|
62
61
  puts sprintf("%3d %3d %s", c.lft, c.rgt, c.body)
63
62
  # p c
64
63
  }
65
64
  puts '--1'
66
- c1.comments("ORDER BY lft, rgt").each { |c| puts c.body }
65
+ c1.comments(:order => "lft, rgt").each { |c| puts c.body }
67
66
  puts '--2'
68
- c1.full_comments("ORDER BY lft, rgt").each { |c| puts c.body }
67
+ c1.full_comments(:order => "lft, rgt").each { |c| puts c.body }
69
68
  puts '--3'
70
- c1.direct_comments("ORDER BY lft, rgt").each { |c| puts c.body }
71
- =end
69
+ c1.direct_comments(:order => "lft, rgt").each { |c| puts c.body }
72
70
 
73
71
  assert_equal 6, c1.full_comments.size
74
72
  assert_equal 5, c1.comments.size
@@ -3,16 +3,16 @@ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
3
3
  require 'test/unit'
4
4
  require 'ostruct'
5
5
 
6
- require 'og/mixins/orderable'
7
-
8
6
  require 'og'
7
+ require 'og/mixin/orderable'
9
8
 
10
- $og = Og::Database.new(
11
- :adapter => 'psql',
12
- :database => 'test',
9
+ $og = Og.setup(
10
+ :store => 'psql',
11
+ # :store => :memory,
12
+ :name => 'test',
13
13
  :user => 'postgres',
14
14
  :password => 'navelrulez',
15
- :drop => true
15
+ :destroy => true
16
16
  )
17
17
 
18
18
  class TestCaseOgOrderable < Test::Unit::TestCase # :nodoc: all
@@ -32,7 +32,7 @@ class TestCaseOgOrderable < Test::Unit::TestCase # :nodoc: all
32
32
  property :body, String
33
33
  belongs_to :article, Article
34
34
 
35
- include Og::Orderable, :scope => :article
35
+ include Og::Orderable #, :scope => :article
36
36
 
37
37
  def initialize(body = nil)
38
38
  @body = body
@@ -40,17 +40,17 @@ class TestCaseOgOrderable < Test::Unit::TestCase # :nodoc: all
40
40
  end
41
41
 
42
42
  def test_all
43
- $og.auto_manage_classes
43
+ $og.manage_classes
44
44
 
45
45
  a = Article.create('article')
46
46
  a.save
47
47
 
48
- c1 = Comment.new('1')
49
- a.add_comment(c1)
50
- c2 = Comment.new('2')
51
- a.add_comment(c2)
52
- c3 = Comment.new('3')
53
- a.add_comment(c3)
48
+ c1 = Comment.create('1')
49
+ a.comments << c1
50
+ c2 = Comment.create('2')
51
+ a.comments << c2
52
+ c3 = Comment.create('3')
53
+ a.comments << c3
54
54
 
55
55
  assert_equal 1, c1.position
56
56
  assert_equal 2, c2.position
@@ -63,6 +63,7 @@ class TestCaseOgOrderable < Test::Unit::TestCase # :nodoc: all
63
63
  c3.reload
64
64
 
65
65
  assert_equal 1, c1.position
66
+
66
67
  assert_equal 2, c3.position
67
68
  assert_equal 3, c2.position
68
69
 
@@ -0,0 +1,38 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ require 'test/unit'
4
+ require 'ostruct'
5
+
6
+ require 'og'
7
+ require 'og/mixin/timestamped'
8
+
9
+ $og = Og.setup(
10
+ :store => 'psql',
11
+ :name => 'test',
12
+ :user => 'postgres',
13
+ :password => 'navelrulez',
14
+ :destroy => true
15
+ )
16
+
17
+ class TestCaseOgTimestamped < Test::Unit::TestCase # :nodoc: all
18
+
19
+ class Article
20
+ include Og::Timestamped
21
+ property :body, String
22
+
23
+ def initialize(body = nil)
24
+ @body = body
25
+ end
26
+ end
27
+
28
+ def test_all
29
+ $og.manage_classes
30
+
31
+ a = Article.create('article')
32
+ a.save
33
+
34
+ a = Article[1]
35
+ assert a.create_time
36
+ end
37
+
38
+ end
@@ -0,0 +1,71 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ require 'test/unit'
4
+
5
+ require 'og'
6
+
7
+ class TestCaseOgFilesys < Test::Unit::TestCase # :nodoc: all
8
+ include Og
9
+
10
+ class Comment; end
11
+
12
+ class Article
13
+ property :body, String
14
+ has_many :comment, Comment
15
+
16
+ def initialize(body = nil)
17
+ @body = body
18
+ end
19
+ end
20
+
21
+ class Comment
22
+ property :body, String
23
+ belongs_to :article, Article
24
+
25
+ def initialize(body = nil)
26
+ @body = body
27
+ end
28
+ end
29
+
30
+ class User
31
+ property :name, :name_key => true
32
+ end
33
+
34
+ def setup
35
+ @og = Og.setup(:store => 'filesys', :name => 'test')
36
+ end
37
+
38
+ def teardown
39
+ @og = nil
40
+ end
41
+
42
+ def test_all
43
+ # p Comment.__meta
44
+ # p Article.__meta
45
+
46
+ a1 = Article.new('Article 1')
47
+ @og.store.save(a1)
48
+
49
+ a2 = @og.store.load(1, Article)
50
+
51
+ assert_equal a1.body, a2.body
52
+
53
+ a3 = Article.new('Article 3')
54
+ a3.save
55
+
56
+ @og.store.delete(a3)
57
+
58
+ assert @og.store.load(1, Article)
59
+ assert !@og.store.load(2, Article)
60
+
61
+ a2.delete
62
+
63
+ # a.comments << Comment.new('Comment 1')
64
+ # a.save
65
+ # a = Article[1]
66
+
67
+ @og.store.close
68
+ @og.store.class.destroy(@og.options)
69
+ end
70
+
71
+ end
@@ -0,0 +1,36 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ require 'test/unit'
4
+
5
+ require 'og'
6
+ require 'og/relation'
7
+
8
+ class TestCaseOgRelation < Test::Unit::TestCase # :nodoc: all
9
+ include Og
10
+
11
+ class User
12
+ property :name
13
+ has_many Dummer
14
+ has_many Article
15
+ end
16
+
17
+ class Article
18
+ property :body, String
19
+ end
20
+
21
+ def test_all
22
+ # no-namespace case.
23
+ rel = User.relation(:dummers)
24
+ rel.resolve_target
25
+ assert_equal Dummer, rel.target_class
26
+
27
+ # namespace case.
28
+ rel = User.relation(:articles)
29
+ rel.resolve_target
30
+ assert_equal TestCaseOgRelation::Article, rel.target_class
31
+ end
32
+ end
33
+
34
+ class Dummer
35
+ property :dum, String
36
+ end
@@ -0,0 +1,290 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ #$DBG = true
4
+
5
+ require 'test/unit'
6
+
7
+ require 'og'
8
+
9
+ class TCOgStore < Test::Unit::TestCase # :nodoc: all
10
+ include Og
11
+
12
+ # Not needed thanks to Og's two-pass algorithm.
13
+ # class Comment; end
14
+
15
+ class User
16
+ property :name, Og::VarChar(32), :unique => true
17
+
18
+ def initialize(name = nil)
19
+ @name = name
20
+ end
21
+ end
22
+
23
+ class Category
24
+ property :title, Og::VarChar(32), :unique => true
25
+ joins_many Article
26
+
27
+ def initialize(title = nil)
28
+ @title = title
29
+ end
30
+ end
31
+
32
+ class Article
33
+ property :title, :body, String
34
+ has_many Comment
35
+ has_one :author, User
36
+ refers_to :owner, User
37
+ many_to_many Category
38
+
39
+ def initialize(body = nil)
40
+ @body = body
41
+ end
42
+ end
43
+
44
+ class Comment
45
+ property :body, String
46
+ property :hits, Fixnum
47
+ # lets define the relation name just for fun.
48
+ belongs_to :article, Article
49
+ belongs_to User
50
+
51
+ def initialize(body = nil, user = nil)
52
+ @body = body
53
+ @user = user
54
+ @hits = 0
55
+ end
56
+ end
57
+
58
+ def setup
59
+ @og = nil
60
+ end
61
+
62
+ def teardown
63
+ @og.store.close
64
+ @og.store.class.destroy(@og.options)
65
+ @og = nil
66
+ end
67
+
68
+ =begin
69
+ def test_psql
70
+ @og = Og.setup(
71
+ :destroy => true,
72
+ :store => :psql,
73
+ :name => 'test',
74
+ :user => 'postgres',
75
+ :password => 'navelrulez'
76
+ )
77
+ features_test
78
+ conversions_test
79
+ end
80
+ =end
81
+ =begin
82
+ def test_mysql
83
+ @og = Og.setup(
84
+ :destroy => true,
85
+ :store => :mysql,
86
+ :name => 'test',
87
+ :user => 'root',
88
+ :password => 'navelrulez'
89
+ )
90
+ features_test
91
+ # conversions_test
92
+ end
93
+ =end
94
+ #=begin
95
+ def test_sqlite
96
+ @og = Og.setup(
97
+ :destroy => true,
98
+ :store => :sqlite,
99
+ :name => 'test'
100
+ )
101
+ features_test
102
+ conversions_test
103
+ end
104
+ #=end
105
+ =begin
106
+ def test_memory
107
+ @og = Og.setup(
108
+ :store => :memory,
109
+ :name => :test,
110
+ :destroy => true
111
+ )
112
+ features_test
113
+ end
114
+ =end
115
+
116
+ def features_test
117
+ u = User.create('gmosx')
118
+
119
+ a1 = Article.new('Article 1')
120
+ @og.store.save(a1)
121
+
122
+ a2 = @og.store.load(1, Article)
123
+
124
+ assert_equal a1.body, a2.body
125
+
126
+ a3 = Article.create do |a|
127
+ a.title = 'Title 3'
128
+ a.body = 'Article 3'
129
+ end
130
+
131
+ a0 = Article.one(:condition => "body='Article 3'")
132
+ assert_equal 'Article 3', a0.body
133
+
134
+ @og.store.delete(a3)
135
+
136
+ assert @og.store.load(1, Article)
137
+ # assert !Article[2]
138
+ assert Article.load(1)
139
+
140
+ a2.delete
141
+
142
+ a4 = Article.new('Article 4')
143
+ a4.author = u
144
+ a4.owner = u
145
+ a4.save
146
+
147
+ # add some children.
148
+
149
+ a4.comments << Comment.new('Comment 1', u)
150
+ a4.comments.push(Comment.new('Comment 2', u))
151
+ a4.comments.add(Comment.new('Comment 3', u))
152
+
153
+ assert_equal 3, a4.comments.size
154
+
155
+ assert_not_equal a4.comments[1].body, a4.comments[0].body
156
+
157
+
158
+ assert_not_equal a4.comments[0].body, a4.comments[1].body
159
+
160
+ c1 = Comment.new('Comment 4')
161
+ c1.article = a4
162
+ c1.user = u
163
+ c1.save
164
+
165
+ c1.reload
166
+ assert_equal 'Comment 4', c1.body
167
+
168
+ # count
169
+
170
+ assert_equal 4, @og.store.count(:class => Comment)
171
+ assert_equal 1, @og.store.count(:class => Comment, :condition => "body = 'Comment 4'")
172
+ assert_equal 4, Comment.count
173
+ assert_equal 1, Comment.count(:condition => "body = 'Comment 2'")
174
+
175
+ # update_properties
176
+
177
+ Comment.update_properties('@hits = @hits + 1')
178
+ cc = Comment[1]
179
+ assert_equal 1, cc.hits
180
+ Comment.update_properties('@hits = @hits + 1', :condition => 'oid = 1')
181
+ cc.reload
182
+ assert_equal 2, cc.hits
183
+ cc.update_properties('@hits = @hits + 1')
184
+ cc.reload
185
+ assert_equal 3, cc.hits
186
+
187
+ # update selected properties.
188
+
189
+ cc.hits = 5
190
+ cc.update(:hits)
191
+ assert_equal 5, cc.hits
192
+ cc.reload
193
+ assert_equal 5, cc.hits
194
+
195
+ cc.hits += 1
196
+ cc.body = 'Wow!'
197
+ cc.update(:hits, :body)
198
+ cc.reload
199
+ assert_equal 'Wow!', cc.body
200
+
201
+ # join
202
+
203
+ c3 = Comment.one(:condition => "body = 'Comment 4'", :include => :user)
204
+ assert_equal 'Comment 4', c3.body
205
+ # is eagerly loaded.
206
+ assert_equal 'gmosx', c3.user.name
207
+ assert_equal 'Article 4', c3.article.body
208
+
209
+ comments = a4.comments(:reload => true, :include => [:user, :article])
210
+ assert_equal 'gmosx', comments[0].user.name
211
+ assert_equal 'Article 4', comments.first.article.body
212
+
213
+ # thanks to reloading detects the manually added
214
+ # comment.
215
+
216
+ assert_equal 4, a4.comments(:reload => true).size
217
+
218
+ a4.comments.delete(c1)
219
+ assert_equal 3, a4.comments.size
220
+
221
+ assert_equal 3, @og.store.count(:class => Comment)
222
+
223
+ a4.comments.clear
224
+ assert_equal 0, a4.comments.size
225
+
226
+ # has_one
227
+
228
+ assert_equal 'gmosx', a4.author.name
229
+
230
+ # refers_to
231
+
232
+ assert_equal 'gmosx', a4.owner.name
233
+
234
+ # generated finders
235
+
236
+ assert User.respond_to?(:find_by_name)
237
+ assert Comment.respond_to?(:find_by_body)
238
+
239
+ u = User.find_by_name('gmosx')
240
+ assert_equal 'gmosx', u.name
241
+
242
+ # inspection.
243
+
244
+ assert_equal 2, Comment.relations.size
245
+
246
+ rel = Comment.relation(:article)
247
+ assert_equal Og::BelongsTo, rel.class
248
+
249
+ # joins_many / many_to_many relations.
250
+
251
+ c1 = Category.create('News')
252
+ c2 = Category.create('Sports')
253
+ a = Article.create('Hello')
254
+ a.categories << c1
255
+ a.save
256
+ a.categories << c2
257
+ a.save
258
+
259
+ assert_equal 2, a.categories.size
260
+
261
+ a = Article.find_by_body('Hello').first
262
+ assert_equal 2, a.categories.size
263
+ assert_equal 'News', a.categories[0].title
264
+
265
+ c = Category.find_by_title('News')
266
+ assert_equal 1, c.articles.size
267
+ end
268
+
269
+ def conversions_test
270
+ store = @og.store
271
+
272
+ assert_equal '13', store.quote(13)
273
+ assert_equal '13.23', store.quote(13.23)
274
+ assert_equal "'can''t quote'", store.quote("can't quote")
275
+
276
+ t = Time.now
277
+
278
+ assert_equal t.day, store.parse_timestamp(store.timestamp(t)).day
279
+ assert_equal t.year, store.parse_timestamp(store.timestamp(t)).year
280
+ assert_equal t.month, store.parse_timestamp(store.timestamp(t)).month
281
+ assert_equal t.hour, store.parse_timestamp(store.timestamp(t)).hour
282
+ assert_equal t.min, store.parse_timestamp(store.timestamp(t)).min
283
+ assert_equal t.sec, store.parse_timestamp(store.timestamp(t)).sec
284
+
285
+ d = Date.new
286
+
287
+ assert_equal d, store.parse_date(store.date(d))
288
+ end
289
+
290
+ end