og 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG +77 -0
  2. data/INSTALL +3 -0
  3. data/README +5 -3
  4. data/Rakefile +148 -5
  5. data/benchmark/bench.rb +1 -1
  6. data/doc/AUTHORS +4 -4
  7. data/doc/RELEASES +41 -1
  8. data/examples/mock_example.rb +1 -1
  9. data/examples/mysql_to_psql.rb +1 -1
  10. data/examples/run.rb +1 -1
  11. data/install.rb +1 -1
  12. data/lib/og.rb +4 -2
  13. data/lib/og/{adapter.rb → adapters/base.rb} +334 -152
  14. data/lib/og/adapters/filesys.rb +3 -7
  15. data/lib/og/adapters/mysql.rb +5 -9
  16. data/lib/og/adapters/oracle.rb +5 -9
  17. data/lib/og/adapters/psql.rb +5 -9
  18. data/lib/og/adapters/sqlite.rb +5 -9
  19. data/lib/og/adapters/sqlserver.rb +5 -9
  20. data/lib/og/database.rb +13 -11
  21. data/lib/og/enchant.rb +1 -1
  22. data/lib/og/errors.rb +21 -0
  23. data/lib/og/meta.rb +10 -9
  24. data/lib/og/mixins/hierarchical.rb +4 -4
  25. data/lib/og/mixins/orderable.rb +1 -1
  26. data/lib/og/mixins/timestamped.rb +24 -0
  27. data/lib/og/mixins/tree.rb +3 -1
  28. data/lib/og/testing/mock.rb +2 -2
  29. data/lib/og/typemacros.rb +1 -1
  30. data/lib/og/validation.rb +4 -4
  31. data/test/og/{tc_filesys.rb → adapters/tc_filesys.rb} +1 -1
  32. data/test/og/{tc_sqlite.rb → adapters/tc_sqlite.rb} +3 -4
  33. data/test/og/{tc_sqlserver.rb → adapters/tc_sqlserver.rb} +5 -2
  34. data/test/og/mixins/tc_hierarchical.rb +0 -1
  35. data/test/og/mixins/tc_orderable.rb +0 -1
  36. data/test/og/tc_automanage.rb +3 -2
  37. data/test/og/tc_lifecycle.rb +15 -14
  38. data/test/og/tc_many_to_many.rb +0 -1
  39. data/test/og/tc_meta.rb +5 -5
  40. data/test/og/tc_validation.rb +1 -1
  41. data/test/tc_og.rb +0 -20
  42. metadata +33 -34
  43. data/examples/test.db +0 -0
  44. data/lib/og/connection.rb +0 -325
  45. data/lib/og/observer.rb +0 -53
  46. data/test/og/tc_observer.rb +0 -85
Binary file
@@ -1,325 +0,0 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: connection.rb 326 2005-03-28 11:07:17Z gmosx $
4
-
5
- module Og;
6
-
7
- require 'glue/property'
8
- require 'glue/array'
9
- require 'glue/time'
10
-
11
- # A Connection to the Database. This file defines the skeleton
12
- # functionality. A backend specific implementation file (driver)
13
- # implements all methods.
14
- #
15
- #--
16
- # - support caching.
17
- # - support prepared statements.
18
- #++
19
-
20
- class Connection
21
-
22
- # The Og database object.
23
-
24
- attr_reader :db
25
-
26
- # The actual connection to the backend store.
27
-
28
- attr_accessor :store
29
-
30
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
31
- # :section: Backend connection methods.
32
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33
-
34
- # Initialize a connection to the database.
35
-
36
- def initialize(db)
37
- @db = db
38
- Logger.debug "Created DB connection." if $DBG
39
- end
40
-
41
- # Close the connection to the database.
42
-
43
- def close
44
- Logger.debug "Closed DB connection." if $DBG
45
- end
46
-
47
- # Create the managed object table. The properties of the
48
- # object are mapped to the table columns. Additional sql relations
49
- # and constrains are created (indicices, sequences, etc).
50
-
51
- def create_table(klass)
52
- raise 'Not implemented!'
53
- end
54
-
55
- # Drop the managed object table.
56
-
57
- def drop_table(klass)
58
- exec "DROP TABLE #{klass::DBTABLE}"
59
- end
60
-
61
- # Prepare an sql statement.
62
-
63
- def prepare(sql)
64
- raise 'Not implemented!'
65
- end
66
-
67
- # Execute an SQL query and return the result.
68
-
69
- def query(sql)
70
- raise 'Not implemented!'
71
- end
72
-
73
- # Execute an SQL query, no result returned.
74
-
75
- def exec(sql)
76
- raise 'Not implemented!'
77
- end
78
- alias_method :execute, :exec
79
-
80
- # Start a new transaction.
81
-
82
- def start
83
- exec 'START TRANSACTION'
84
- end
85
-
86
- # Commit a transaction.
87
-
88
- def commit
89
- exec 'COMMIT'
90
- end
91
-
92
- # Rollback a transaction.
93
-
94
- def rollback
95
- exec 'ROLLBACK'
96
- end
97
-
98
- # Transaction helper. In the transaction block use
99
- # the db pointer to the backend.
100
-
101
- def transaction(&block)
102
- begin
103
- start
104
- yield(self)
105
- commit
106
- rescue => ex
107
- Logger.error "DB Error: ERROR IN TRANSACTION"
108
- Logger.error "#{ex}"
109
- Logger.error "#{ex.backtrace}"
110
- rollback
111
- end
112
- end
113
-
114
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
115
- # :section: Deserialization methods.
116
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
117
-
118
- # Is the given resultset valid?
119
-
120
- def valid_res?(res)
121
- return !(res.nil?)
122
- end
123
-
124
- # Read (deserialize) one row of the resultset.
125
-
126
- def read_one(res, klass)
127
- raise 'Not implemented!'
128
- end
129
-
130
- # Read (deserialize) all rows of the resultset.
131
-
132
- def read_all(res, klass)
133
- raise 'Not implemented!'
134
- end
135
-
136
- # Read the first column of the resultset as an Integer.
137
-
138
- def read_int(res, idx = 0)
139
- raise 'Not implemented!'
140
- end
141
-
142
- # Get a row from the resultset.
143
-
144
- def get_row(res)
145
- return res
146
- end
147
-
148
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
149
- # :section: Managed object methods.
150
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
151
-
152
- # Save an object to the database. Insert if this is a new object or
153
- # update if this is already stored in the database.
154
-
155
- def save(obj)
156
- if obj.oid
157
- # object allready inserted, update!
158
- obj.og_update(self)
159
- else
160
- # not in the database, insert!
161
- obj.og_insert(self)
162
- end
163
- end
164
- alias_method :<<, :save
165
- alias_method :put, :save
166
-
167
- # Force insertion of managed object.
168
-
169
- def insert(obj)
170
- obj.og_insert(self)
171
- end
172
-
173
- # Force update of managed object.
174
-
175
- def update(obj)
176
- obj.og_update(self)
177
- end
178
-
179
- # Update only specific fields of the managed object.
180
- #
181
- # Input:
182
- # sql = the sql code to updated the properties.
183
- #
184
- # WARNING: the object in memory is not updated.
185
- #--
186
- # TODO: should update the object in memory.
187
- #++
188
-
189
- def update_properties(update_sql, obj_or_oid, klass = nil)
190
- oid = obj_or_oid.to_i
191
- klass = obj_or_oid.class unless klass
192
-
193
- exec "UPDATE #{klass::DBTABLE} SET #{update_sql} WHERE oid=#{oid}"
194
- end
195
- alias_method :pupdate, :update_properties
196
- alias_method :update_propery, :update_properties
197
-
198
- # Load an object from the database.
199
- #
200
- # Input:
201
- # oid = the object oid, OR the object name.
202
-
203
- def load(oid, klass)
204
- if oid.to_i > 0 # a valid Fixnum ?
205
- load_by_oid(oid, klass)
206
- else
207
- load_by_name(oid, klass)
208
- end
209
- end
210
- alias_method :get, :load
211
-
212
- # Load an object by oid.
213
-
214
- def load_by_oid(oid, klass)
215
- res = query "SELECT * FROM #{klass::DBTABLE} WHERE oid=#{oid}"
216
- read_one(res, klass)
217
- end
218
- alias_method :get_by_oid, :load_by_oid
219
-
220
- # Load an object by name.
221
-
222
- def load_by_name(name, klass)
223
- res = query "SELECT * FROM #{klass::DBTABLE} WHERE name='#{name}'"
224
- read_one(res, klass)
225
- end
226
- alias_method :get_by_name, :load_by_name
227
-
228
- # Load all objects of the given klass.
229
- # Used to be called 'collect' in an earlier version.
230
-
231
- def load_all(klass, extrasql = nil)
232
- res = query "SELECT * FROM #{klass::DBTABLE} #{extrasql}"
233
- read_all(res, klass)
234
- end
235
- alias_method :get_all, :load_all
236
-
237
- # Perform a standard SQL query to the database. Deserializes the
238
- # results.
239
-
240
- def select(sql, klass)
241
- unless sql =~ /SELECT/i
242
- sql = "SELECT * FROM #{klass::DBTABLE} WHERE #{sql}"
243
- end
244
-
245
- res = query(sql)
246
- read_all(res, klass)
247
- end
248
-
249
- # Optimized for one result.
250
-
251
- def select_one(sql, klass)
252
- unless sql =~ /SELECT/i
253
- sql = "SELECT * FROM #{klass::DBTABLE} WHERE #{sql}"
254
- end
255
-
256
- res = query(sql)
257
- read_one(res, klass)
258
- end
259
-
260
- # Perform a count query.
261
-
262
- def count(sql, klass = nil)
263
- unless sql =~ /SELECT/i
264
- sql = "SELECT COUNT(*) FROM #{klass::DBTABLE} WHERE #{sql}"
265
- end
266
-
267
- res = query(sql)
268
- return read_int(res)
269
- end
270
-
271
- # Delete an object from the database. Allways perform a deep delete.
272
- #
273
- # No need to optimize here with pregenerated code. Deletes are
274
- # not used as much as reads or writes.
275
- #
276
- # Input:
277
- #
278
- # obj_or_oid = Object or oid to delete.
279
- # klass = Class of object (can be nil if an object is passed)
280
- #
281
- #--
282
- # TODO: pre evaluate for symmetry to the other methods
283
- #++
284
-
285
- def delete(obj_or_oid, klass = nil, cascade = true)
286
- oid = obj_or_oid.to_i
287
- klass = obj_or_oid.class unless klass
288
-
289
- # this is a class callback!
290
-
291
- if klass.respond_to?(:og_pre_delete)
292
- klass.og_pre_delete(self, obj_or_oid)
293
- end
294
-
295
- # TODO: implement this as stored procedure? naaah.
296
- # TODO: also handle many_to_many relations.
297
-
298
- transaction do |tx|
299
- tx.exec "DELETE FROM #{klass::DBTABLE} WHERE oid=#{oid}"
300
- if cascade and klass.__meta.include?(:descendants)
301
- klass.__meta[:descendants].each do |dclass, linkback|
302
- tx.exec "DELETE FROM #{dclass::DBTABLE} WHERE #{linkback}=#{oid}"
303
- end
304
- end
305
- end
306
- end
307
- alias_method :delete!, :delete
308
-
309
- protected
310
-
311
- # Handles an adapter exception.
312
-
313
- def handle_db_exception(ex, sql = nil)
314
- Logger.error "DB error #{ex}, [#{sql}]"
315
- Logger.error ex.backtrace.join("\n")
316
- raise SqlException.new(ex, sql) if Og.raise_db_exceptions
317
-
318
- # FIXME: should return :error or something.
319
-
320
- return nil
321
- end
322
-
323
- end
324
-
325
- end
@@ -1,53 +0,0 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: observer.rb 281 2005-03-10 12:24:14Z gmosx $
4
-
5
- module Og
6
-
7
- # Classes that include this module can be tracked by
8
- # Observers. The observer mechanism utilizes duck typing
9
- # so you can attach any class that responds to the
10
- # Og lifycycle callback methods. However, classes extended
11
- # from the Observer base class are typically used.
12
-
13
- module Observable
14
- def add_observer(*observer)
15
- for o in observer.flatten
16
- meta :og_observers, o
17
- self.og_db.adapter.eval_lifecycle_methods(self, self.og_db)
18
- end
19
- end
20
- end
21
-
22
- # Observers are attached to managed classes to track their
23
- # Lifecycle. This way, the 'polution' of the original class
24
- # with excess responsibility is avoided.
25
- #
26
- # An observer can implement the standard Og lifecycle
27
- # callbacks:
28
- #
29
- # * og_pre_read
30
- # * og_post_read
31
- # * og_pre_insert
32
- # * og_post_insert
33
- # * og_pre_update
34
- # * og_post_update
35
- # * og_pre_insert_update
36
- # * og_post_insert_update
37
- # * self.og_pre_delete
38
- #
39
- # Based on code from ActiveRecord (http://www.rubyonrails.com)
40
-
41
- class Observer
42
- include Singleton
43
-
44
- # Attaches the observer to the supplied classes.
45
-
46
- def self.observe(*classes)
47
- for c in classes.flatten
48
- c.meta :og_observers, self
49
- end
50
- end
51
- end
52
-
53
- end
@@ -1,85 +0,0 @@
1
- $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
-
3
- require 'test/unit'
4
- require 'ostruct'
5
-
6
- require 'og'
7
-
8
- class TC_OgObserver < Test::Unit::TestCase # :nodoc: all
9
- include N
10
-
11
- class User
12
- property :name
13
- end
14
-
15
- class Article
16
- property :name, String
17
- property :age, Fixnum
18
-
19
- def initialize (name = nil, age = nil)
20
- @name, @age = name, age
21
- end
22
- end
23
-
24
- # Example of a simple class that acts as an observer.
25
-
26
- class ArticleObserver
27
- attr :count
28
-
29
- def initialize
30
- @count = 0
31
- end
32
-
33
- def og_pre_insert(conn, obj)
34
- @count += 1
35
- end
36
- end
37
-
38
- # Rails style observer, baaah...
39
-
40
- class MultiObserver < Og::Observer
41
- observe Article, User
42
-
43
- attr :count
44
-
45
- def initialize
46
- @count = 0
47
- end
48
-
49
- def og_pre_insert(conn, obj)
50
- @count += 1
51
- end
52
- end
53
-
54
- def setup
55
- end
56
-
57
- def teardown
58
- end
59
-
60
- def test_all
61
- config = {
62
- :adapter => 'psql',
63
- :database => 'test',
64
- :user => 'postgres',
65
- :password => 'navelrulez',
66
- :connection_count => 2
67
- }
68
-
69
- Og::Database.drop_db!(config)
70
- og = Og::Database.new(config)
71
-
72
- og.get_connection
73
-
74
- ao = ArticleObserver.new
75
- Article.add_observer(ao)
76
- Article.create('Hello', 5)
77
-
78
- assert_equal 1, ao.count
79
- assert_equal 1, MultiObserver.instance.count
80
-
81
- og.put_connection
82
- og.shutdown
83
- end
84
-
85
- end