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/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'