og 0.16.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
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/examples/run.rb CHANGED
@@ -1,8 +1,4 @@
1
1
  # A simple example to demonstrate the Og library.
2
- #
3
- # * George Moschovitis <gm@navel.gr>
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: run.rb 1 2005-04-11 11:04:30Z gmosx $
6
2
 
7
3
  require 'og'
8
4
 
@@ -13,7 +9,7 @@ $DBG = true
13
9
  # A child class.
14
10
 
15
11
  class Comment
16
- prop_accessor :body, String
12
+ property :body, String
17
13
 
18
14
  def initialize(body = nil)
19
15
  @body = body
@@ -24,20 +20,10 @@ class Comment
24
20
  end
25
21
  end
26
22
 
27
- # forward declaration
28
- class ArticleComment < Comment; end
23
+ # = A Parent class.
29
24
 
30
- # forward declaration
31
- class UserComment < Comment; end
32
-
33
- # forward declaration
34
- class Part; end
35
-
36
- # = A Parent class
37
- #
38
25
  class User
39
- prop_accessor :name, String
40
-
26
+ property :name, String, :unique => true
41
27
  has_many :comments, UserComment
42
28
 
43
29
  def initialize(name = nil)
@@ -53,31 +39,44 @@ end
53
39
  # A parent class.
54
40
 
55
41
  class Article
56
- prop_accessor :title, String
57
- prop_accessor :body, String
42
+ property :title, String
43
+ property :body, String
44
+
58
45
  # override the default O->R mapping
59
- prop_accessor :level, Fixnum, :sql => "smallint DEFAULT 1"
46
+
47
+ property :level, Fixnum, :sql => "smallint DEFAULT 1"
48
+
60
49
  # store a Ruby Hash in the Database. YAML
61
50
  # is used for serializing the attribute.
62
51
  # no need to define the class, but you can if you want.
63
- prop_accessor :options
52
+
53
+ property :options
54
+
64
55
  # exactly like the standard Ruby attr creates only the reader.
56
+
65
57
  prop :create_time, Time
66
58
 
67
59
  # define comment relation:
60
+
68
61
  has_many :comments, ArticleComment
69
62
 
70
63
  has_many :parts, Part
64
+
65
+ # many to many relation.
66
+
67
+ many_to_many Category
71
68
 
72
69
  # define author relation:
70
+
73
71
  belongs_to :author, User
74
72
 
75
73
  # this attribute is NOT stored in the db.
74
+
76
75
  attr_accessor :other_options
77
76
 
78
77
  # Managed object constructors with no args, take *args
79
78
  # as parameter to allow for Mixin chaining.
80
- #
79
+
81
80
  def initialize(title = nil, body = nil)
82
81
  @title, @body = title, body
83
82
  @create_time = Time.now
@@ -93,11 +92,12 @@ end
93
92
  # A parent class.
94
93
 
95
94
  class Category
96
- prop_accessor :title, String
97
- prop_accessor :body, String
95
+ property :title, String
96
+ property :body, String
98
97
 
99
98
  # define a 'many to many' relation.
100
- many_to_many :articles, Article
99
+
100
+ many_to_many Article
101
101
 
102
102
  def initialize(title = nil)
103
103
  @title = title
@@ -108,7 +108,7 @@ end
108
108
  # Article comment.
109
109
 
110
110
  class ArticleComment < Comment
111
- belongs_to :article, Article
111
+ belongs_to Article
112
112
  end
113
113
 
114
114
  # User comment.
@@ -120,8 +120,8 @@ end
120
120
  # Another child class.
121
121
 
122
122
  class Part
123
- prop_accessor :name, String
124
- belongs_to :article, Article
123
+ property :name, String
124
+ belongs_to Article
125
125
 
126
126
  def initialize(name = nil)
127
127
  @name = name
@@ -133,68 +133,50 @@ class Part
133
133
  end
134
134
 
135
135
  # Og configuration.
136
- config = {
137
- :database => "test",
138
- :adapter => "sqlite",
139
- :connection_count => 2
140
- }
141
- =begin
142
- config = {
143
- # :address => "localhost",
144
- :database => "test",
145
- :adapter => "psql",
146
- :user => "postgres",
147
- :password => "navelrulez",
148
- :connection_count => 1
149
- }
150
136
 
151
137
  config = {
152
- :address => "localhost",
153
- :database => "test",
154
- :backend => "mysql",
155
- :user => "root",
156
- :password => "navelrulez",
157
- :connection_count => 1
138
+ :destroy => true, # destroy table created from earlier runs.
139
+ :store => 'psql',
140
+ :name => 'test',
141
+ :user => "postgres",
142
+ :password => "navelrulez"
158
143
  }
159
- =end
160
- # Cleanup the database for earlier executions
161
-
162
- Og::Database.drop!(config)
163
144
 
164
145
  # Initialize Og
165
146
 
166
- db = Og::Database.new(config)
147
+ db = Og.setup(config)
167
148
 
168
149
  # Create some articles
169
150
 
170
- a1 = Article.new("Title1", "Body1")
171
- a1.save!
151
+ a1 = Article.new('Title1', 'Body1')
152
+ a1.save
172
153
 
173
154
  # shortcut
174
- a2 = Article.create("Title2", "Body2")
155
+
156
+ a2 = Article.create('Title2', 'Body2')
175
157
 
176
158
  puts "\n\n"
177
159
  puts "* Get and print all articles:"
178
- articles = Article.all()
160
+ articles = Article.all
179
161
  articles.each { |a| puts a }
180
162
 
181
163
  # Create some comments
182
164
 
183
- c1 = ArticleComment.new("Comment 1")
165
+ c1 = ArticleComment.new('Comment 1')
184
166
  c1.article = a1
185
- c1.save!
167
+ c1.save
186
168
 
187
- c2 = ArticleComment.new("Comment 2")
169
+ c2 = ArticleComment.new('Comment 2')
188
170
  # alternative way to set the parent.
189
171
  c2.article_oid = a1.oid
190
172
  # an alternative way to save
191
- db << c2
173
+ db.store << c2
192
174
 
193
175
  # an alternative (easier and cooler) way to add children in a
194
176
  # has_many relation:
195
- c3 = ArticleComment.new("Comment 3")
177
+ c3 = ArticleComment.new('Comment 3')
196
178
  # add_comment is automatically added by Og.
197
- a1.add_comment(c3)
179
+ a1.comments << c3
198
180
 
199
181
  puts "\n\n"
200
182
  puts "* Print all all comments for article 1:"
@@ -206,11 +188,11 @@ a1.comments.each { |c| puts c }
206
188
  puts "\n\n"
207
189
  puts "* comments with sql finetunings:"
208
190
  # use a standard SQL limit clause
209
- a1.comments("LIMIT 2").each { |c| puts c }
191
+ a1.comments(:limit => 2).each { |c| puts c }
210
192
 
211
193
 
212
194
  # Change a managed object
213
- a1.title = "Changed Title"
195
+ a1.title = 'Changed Title'
214
196
  # Og knows that this is a managed object and executes
215
197
  # an SQL UPDATE instead of an SQL INSERT
216
198
  a1.save!
@@ -220,21 +202,24 @@ Article.all.each { |a| puts a }
220
202
 
221
203
  # The previous command updates the whole object. It is used
222
204
  # when there are many updates or you dont care about speed.
223
- # To update only specific fields use pupdate or properties_update
224
- a2.pupdate "title='A specific title'"
205
+ # You can also update specific fields
206
+ a2.title = 'A specific title'
207
+ a2.update(:title)
225
208
 
226
209
  puts "\n\n"
227
210
  Article.all.each { |a| puts a }
228
211
 
229
212
  # delete an object
213
+ puts '-----------------1'
230
214
  ArticleComment.delete(c3)
215
+ puts '-----------------2'
231
216
 
232
217
  puts "\n\n"
233
218
  ArticleComment.all.each { |a| puts a }
234
219
 
235
220
 
236
221
  # Serialize a hash
237
- a1.options = { "k1" => "val1", "k2" => "val2" }
222
+ a1.options = { :k1 => 'val1', :k2 => 'val2' }
238
223
  a1.save!
239
224
 
240
225
  # lookup an object
@@ -243,15 +228,15 @@ article = Article[a1.oid]
243
228
  puts "\n\n"
244
229
  puts article.options.inspect
245
230
 
246
- u = User.new("gmosx")
231
+ u = User.new('gmosx')
247
232
  u.save!
248
233
 
249
234
  article = Article[1]
250
235
  # you can also lookup by the name property.
251
- article.author = User["gmosx"]
236
+ article.author = User.find_by_name('gmosx')
252
237
  article.save!
253
238
 
254
- part = Part.new("admin")
239
+ part = Part.new('admin')
255
240
  part.article = article
256
241
  part.save!
257
242
 
@@ -260,11 +245,11 @@ article.parts.each { |pa| puts pa }
260
245
  puts "\n\n"
261
246
  puts '---'
262
247
 
263
- c1 = Category.new("Category1").save!
264
- c2 = Category.new("Category2").save!
248
+ c1 = Category.new('Category1').save!
249
+ c2 = Category.new('Category2').save!
265
250
 
266
- article.add_category(c1)
267
- article.add_category(c2)
251
+ article.categories << c1
252
+ article.categories << c2
268
253
 
269
254
  puts '---'
270
255
 
@@ -274,13 +259,13 @@ puts '---'
274
259
 
275
260
  c2.articles.each { |a| puts a.title }
276
261
 
277
- article.delete_category(c1)
262
+ article.categories.delete(c1)
278
263
 
279
264
  puts '---'
280
265
 
281
266
  article.categories.each { |c| puts c.title }
282
267
 
283
268
  # create and save the article in one step.
284
- article = Article.create("title", "body")
269
+ article = Article.create('title', 'body')
285
270
 
286
271
  puts '--', article.oid
data/install.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # * George Moschovitis <gm@navel.gr>
4
4
  # (c) 2004-2005 Navel, all rights reserved.
5
- # $Id: install.rb 1 2005-04-11 11:04:30Z gmosx $
5
+ # $Id: install.rb 32 2005-04-25 12:31:21Z gmosx $
6
6
 
7
7
  require 'rbconfig'
8
8
  require 'ftools'
data/lib/og.rb CHANGED
@@ -1,6 +1,11 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: og.rb 20 2005-04-15 15:18:36Z gmosx $
1
+ # = Og
2
+ #
3
+ # Copyright (c) 2004-2005, George Moschovitis (http://www.gmosx.com)
4
+ # Copyright (c) 2004-2005, Navel Ltd (http://www.navel.gr)
5
+ #
6
+ # Og is copyrighted free software created and maintained by
7
+ # George Moschovitis (mailto:gm@navel.gr) and released under the
8
+ # standard BSD Licence. For details consult the file doc/LICENCE.
4
9
 
5
10
  require 'glue'
6
11
  require 'glue/logger'
@@ -14,8 +19,9 @@ require 'glue/inflector'
14
19
  require 'glue/validation'
15
20
  require 'glue/aspects'
16
21
 
17
- # Og (ObjectGraph) is an efficient, yet simple Object-Relational
18
- # mapping library.
22
+ # Og (ObjectGraph) manages Ruby objects and their relations and
23
+ # provides transparent and efficient object-relational mapping
24
+ # and querying mechanisms.
19
25
  #
20
26
  # === Features
21
27
  #
@@ -23,30 +29,22 @@ require 'glue/aspects'
23
29
  #
24
30
  # + Object-Relational mapping.
25
31
  # + Absolutely no configuration files.
26
- # + Multiple backends (PostgreSQL, MySQL, SQLite, Oracle).
32
+ # + Multiple stores (PostgreSQL, MySQL, SQLite, Oraclei, SqlServer, ..).
33
+ # + Supports non SQL stores.
27
34
  # + ActiveRecord-style meta language and db aware methods.
28
35
  # + Deserialize to Ruby Objects.
29
- # + Deserialize sql join queries to Ruby Objects (temporarily dissabled).
36
+ # + Deserialize sql join queries to Ruby Objects.
37
+ # + Eager associations.
30
38
  # + Serialize arbitrary ruby object graphs through YAML.
31
39
  # + Connection pooling.
32
- # + Thread safety.
40
+ # + Thread safety (temporarily dissabled).
33
41
  # + SQL transactions.
34
- # + Lifecycle callbacks.
35
- # + Lifecycle observers.
42
+ # + Aspect oriented constructs allow interception of lifecycle callbacks.
36
43
  # + Transparent support for cascading deletes for all backends.
37
- # + Hierarchical structures (preorder traversal, materialized paths)
44
+ # + Hierarchical structures (nested sets)
38
45
  # + Works safely as part of distributed application.
39
46
  # + Simple implementation.
40
47
  #
41
- # === Meta language
42
- #
43
- # primary_key :pid (NOT IMPLEMENTED)
44
- # name_key :name (NOT IMPLEMENTED)
45
- # prop_accessor Fixnum, :pid, :sql => "smallint DEFAULT 1"
46
- # has_many Child, :children
47
- # many_to_many Role, :roles
48
- # sql_index :pid
49
- #
50
48
  # === Property Metadata
51
49
  #
52
50
  # Og defines, reserves and uses the following property
@@ -58,64 +56,31 @@ require 'glue/aspects'
58
56
  # [+:unique+]
59
57
  # This value of the property must be unique.
60
58
  #
61
- # [+:name_key+]
62
- # This property is used as name-key.
63
- #
64
59
  # === Design
65
60
  #
66
- # Keep the main classes backend agnostic.
67
- #
68
- # For class ids we use the name instead of a hash. Class ids are
69
- # typically not used in querys, they are stored for completeness.
70
- # If we store a hash we cannot reclaim the class thus invalidating
71
- # the point. Instead of .name(), to_s() is used so the methods
72
- # are more flexible (they accept class names too!!)
73
- #
74
61
  # Og allows the serialization of arbitrary Ruby objects. Just
75
62
  # mark them as Object (or Array or Hash) in the prop_accessor
76
63
  # and the engine will serialize a YAML dump of the object.
77
64
  # Arbitrary object graphs are supported too.
78
65
  #
79
- # This is NOT a singleton, an application may access multiple
80
- # databases.
81
- #
82
- # The og.xxx methods are more flexible and allow you to use
83
- # multiple databases for example.
84
- #
85
- # === Managed Objects Lifecycle Callbacks
86
- #
87
- # * og_pre_read
88
- # * og_post_read
89
- # * og_pre_insert
90
- # * og_post_insert
91
- # * og_pre_update
92
- # * og_post_update
93
- # * og_pre_insert_update
94
- # * og_post_insert_update
95
- # * self.og_pre_delete
66
+ # === Lifecycle Callbacks
96
67
  #
97
- # A class level callback is used for delete because typically you call
98
- # delete with an oid and not an object to avoid a deserialization.
99
- #
100
- # === Future
101
- #
102
- # * Support prepared statements (pgsql)
103
- # * Support stored procedures (pgsql)
104
- # * Support caching.
105
- # * Deserialize to OpenStruct.
106
- # * Better documentation.
68
+ # * og_read
69
+ # * og_insert
70
+ # * og_update
71
+ # * og_delete
107
72
 
108
73
  module Og
109
74
 
110
75
  # The version.
111
76
 
112
- Version = '0.16.0'
77
+ Version = '0.17.0'
113
78
 
114
79
  # Library path.
115
80
 
116
81
  LibPath = File.dirname(__FILE__)
117
82
 
118
- # If true, check for implicti changes in the object
83
+ # If true, check for implicit changes in the object
119
84
  # graph. For example when you add an object to a parent
120
85
  # the object might be removed from his previous parent.
121
86
  # In this case Og emmits a warning.
@@ -128,63 +93,35 @@ module Og
128
93
 
129
94
  mattr_accessor :read_only_mode, false
130
95
 
131
- # If true, the library automatically 'enchants' managed classes.
132
- # In enchant mode, special db aware methods are added to
133
- # managed classes and instances.
134
- # If false, Og enchants only classes that define properties.
135
-
136
- mattr_accessor :enchant_managed_classes, true
137
-
138
- # If true, use Ruby's advanced introspection capabilities to
139
- # automatically manage classes tha define properties.
140
-
141
- mattr_accessor :auto_manage_classes, true
142
-
143
- # If true, automatically include the Og meta-language into Module.
144
- # If false, the polution of the Module object is avoided. However
145
- # if you include a prop_accessor or a managed Mixin in your
146
- # object MetaLanguage gets automatically extended in the class.
147
-
148
- mattr_accessor :include_meta_language, true
149
-
150
- # Attach the following prefix to all generated SQL table names.
96
+ # Prepend the following prefix to all generated SQL table names.
151
97
  # Usefull on hosting scenarios where you have to run multiple
152
98
  # web applications/sites on a single database.
99
+ #
100
+ # Don't set the table_prefix to nil, or you may face problems
101
+ # with reserved words on some RDBM systems. For example User
102
+ # maps to user which is reserved in postgresql). The prefix
103
+ # should start with an alphanumeric character to be compatible
104
+ # with all RDBM systems (most notable Oracle).
105
+ #--
106
+ # TODO: move this to the sql store.
107
+ #++
153
108
 
154
- mattr_accessor :table_prefix, nil
109
+ mattr_accessor :table_prefix, 'og'
155
110
 
156
111
  # If true, Og tries to create/update the schema in the
157
- # data store. For production/live environments set this to false
158
- # and only set to true when the object model is upadated.
159
- # For debug/development environments this should stay true
160
- # for convienience.
112
+ # data store. For production/live environments set this to
113
+ # false and only set to true when the object model is
114
+ # upadated. For debug/development environments this should
115
+ # stay true for convienience.
161
116
 
162
117
  mattr_accessor :create_schema, true
163
118
 
164
- # If true raises exceptions on database errors, usefull when
119
+ # If true raises exceptions on store errors, usefull when
165
120
  # debugging. For production environments it should probably be
166
121
  # set to false to make the application more fault tolerant.
167
122
 
168
- mattr_accessor :raise_db_exceptions, true
169
-
170
- # The active database. Og allows you to access multiple
171
- # databases from a single application.
123
+ mattr_accessor :raise_store_exceptions, true
172
124
 
173
- mattr_accessor :db
174
-
175
- # Set the active database.
176
-
177
- def self.use(db)
178
- @@db = db
179
- @@db.get_connection
180
- end
181
-
182
- # The adapter of the active database.
183
-
184
- def self.adapter
185
- @@db.adapter
186
- end
187
-
188
125
  # Marker module. If included in a class, the Og automanager
189
126
  # ignores this class.
190
127
 
@@ -194,5 +131,7 @@ end
194
131
 
195
132
  # gmosx: leave this here.
196
133
 
197
- require 'og/database'
134
+ require 'og/manager'
135
+ require 'og/errors'
136
+ require 'og/types'
198
137
  require 'og/validation'