og 0.9.5 → 0.10.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.
@@ -0,0 +1,268 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: database.rb 255 2005-02-10 12:45:32Z gmosx $
4
+
5
+ require 'glue/logger'
6
+ require 'glue/attribute'
7
+ require 'glue/property'
8
+ require 'glue/array'
9
+ require 'glue/hash'
10
+ require 'glue/time'
11
+ require 'glue/pool'
12
+
13
+ require 'og/enchant'
14
+ require 'og/meta'
15
+
16
+ class Og
17
+
18
+ # Encapsulates an Og Database.
19
+
20
+ class Database
21
+ include Og::Enchant
22
+
23
+ # Managed class metadata
24
+
25
+ class ManagedClassMeta
26
+ # The managed class.
27
+ attr_accessor :klass
28
+
29
+ # A mapping of the database fields to the object properties.
30
+ attr_accessor :field_index
31
+
32
+ def initialize(klass = nil)
33
+ @klass = klass
34
+ @field_index = {}
35
+ end
36
+ end
37
+
38
+ # hash of configuration options.
39
+
40
+ attr_accessor :config
41
+
42
+ # The adapter that comunicates with the backend
43
+ # datastore.
44
+
45
+ attr_accessor :adapter
46
+
47
+ # Pool of connections.
48
+
49
+ attr_accessor :connection_pool
50
+
51
+ # Managed classes.
52
+
53
+ attr_accessor :managed_classes
54
+
55
+ # Initialize the database interface.
56
+
57
+ def initialize(config)
58
+ @config = config
59
+
60
+ # populate with default options if needed.
61
+ @config[:connection_count] ||= 1
62
+
63
+ Logger.info "Connecting to database '#{@config[:database]}' using the '#{@config[:adapter]}' adapter."
64
+
65
+ @adapter = Adapter.for_name(@config[:adapter])
66
+
67
+ @connection_pool = N::Pool.new
68
+ @managed_classes = N::SafeHash.new
69
+
70
+ @config[:connection_count].times do
71
+ # @connection_pool << Og::Connection.new(self)
72
+ @connection_pool << @adapter.new_connection(self)
73
+ end
74
+
75
+ # gmosx, FIXME: this automanage code is not elegant and slow
76
+ # should probably recode this, along with glue/property.rb
77
+
78
+ if Og.auto_manage_classes
79
+ # automatically manage classes with properties and metadata.
80
+ # gmosx: Any idea how to optimize this?
81
+
82
+ classes_to_manage = []
83
+
84
+ ObjectSpace.each_object(Class) do |c|
85
+ if c.respond_to?(:__props) and c.__props
86
+ classes_to_manage << c
87
+ end
88
+ end
89
+
90
+ Logger.info "Og auto manages the following classes:"
91
+ Logger.info "#{classes_to_manage.inspect}"
92
+
93
+ manage_classes(*classes_to_manage)
94
+ end
95
+
96
+ # use the newly created database.
97
+ Og.use(self)
98
+ end
99
+
100
+ # Shutdown the database interface.
101
+
102
+ def shutdown
103
+ for con in @connection_pool
104
+ con.close()
105
+ end
106
+ end
107
+ alias_method :close, :shutdown
108
+
109
+ # Get a connection from the pool to access the database.
110
+ # Stores the connection in a thread-local variable.
111
+
112
+ def get_connection
113
+ thread = Thread.current
114
+
115
+ unless conn = thread[:og_conn]
116
+ conn = @connection_pool.pop()
117
+ thread[:og_conn] = conn
118
+ end
119
+
120
+ return conn
121
+ end
122
+ alias_method :connection, :get_connection
123
+
124
+ # Restore an unused connection to the pool.
125
+
126
+ def put_connection
127
+ thread = Thread.current
128
+
129
+ if conn = thread[:og_conn]
130
+ thread[:og_conn] = nil
131
+ return @connection_pool.push(conn)
132
+ end
133
+ end
134
+
135
+ # Utility method, automatically restores a connection to the pool.
136
+
137
+ def connect(&block)
138
+ result = nil
139
+
140
+ begin
141
+ conn = get_connection
142
+ result = yield(conn)
143
+ ensure
144
+ put_connection
145
+ end
146
+
147
+ return result
148
+ end
149
+ alias_method :open, :connect
150
+
151
+
152
+ # Register a standard Ruby class as managed.
153
+
154
+ def manage(klass)
155
+ return if managed?(klass) or klass.ancestors.include?(Og::Unmanageable)
156
+
157
+ @managed_classes[klass] = ManagedClassMeta.new(klass)
158
+
159
+ # Add standard og methods to the class.
160
+ convert(klass)
161
+
162
+ # Add helper methods to the class.
163
+ enchant(klass) if Og.enchant_managed_classes
164
+ end
165
+
166
+ # Helper method to set multiple managed classes.
167
+
168
+ def manage_classes(*klasses)
169
+ for klass in klasses
170
+ manage(klass)
171
+ end
172
+ end
173
+
174
+ # Stop managing a Ruby class
175
+
176
+ def unmanage(klass)
177
+ @managed_classes.delete(klass)
178
+ end
179
+
180
+ # Is this class managed?
181
+ #
182
+ def managed?(klass)
183
+ return @managed_classes.include?(klass)
184
+ end
185
+
186
+ # Add standard og functionality to the class
187
+
188
+ def convert(klass)
189
+ # gmosx: this check is needed to allow the developer to customize
190
+ # the sql generated for oid
191
+
192
+ @adapter.eval_og_oid(klass) unless klass.instance_methods.include?(:oid)
193
+
194
+ klass.class_eval %{
195
+ DBTABLE = "#{Adapter.table(klass)}"
196
+ DBSEQ = "#{Adapter.table(klass)}_oid_seq"
197
+
198
+ def to_i()
199
+ @oid
200
+ end
201
+ }
202
+
203
+ # Create the schema for this class if not available.
204
+ @adapter.create_table(klass, self)
205
+
206
+ # Precompile some code that gets executed all the time.
207
+ # Deletion code is not precompiled, because it is not used
208
+ # as frequently.
209
+
210
+ @adapter.eval_og_insert(klass, self)
211
+ @adapter.eval_og_update(klass, self)
212
+ @adapter.eval_og_read(klass, self)
213
+ end
214
+
215
+ # Automatically wrap connection methods.
216
+
217
+ def self.wrap_method(method, args)
218
+ args = args.split(/,/)
219
+ class_eval %{
220
+ def #{method}(#{args.join(", ")})
221
+ thread = Thread.current
222
+
223
+ unless conn = thread[:og_conn]
224
+ conn = @connection_pool.pop()
225
+ thread[:og_conn] = conn
226
+ end
227
+
228
+ return conn.#{method}(#{args.collect {|a| a.split(/=/)[0]}.join(", ")})
229
+ end
230
+ }
231
+ end
232
+
233
+ wrap_method :db, ''
234
+ wrap_method :create_table, 'klass'
235
+ wrap_method :drop_table, 'klass'
236
+ wrap_method :save, 'obj'; alias_method :<<, :save; alias_method :put, :save
237
+ wrap_method :insert, 'obj'
238
+ wrap_method :update, 'obj'
239
+ wrap_method :update_properties, 'update_sql, obj_or_oid, klass = nil'
240
+ wrap_method :pupdate, 'update_sql, obj_or_oid, klass = nil'
241
+ wrap_method :load, 'oid, klass'; alias_method :get, :load
242
+ wrap_method :load_by_oid, 'oid, klass'
243
+ wrap_method :load_by_name, 'name, klass'
244
+ wrap_method :load_all, 'klass, extrasql = nil'
245
+ wrap_method :select, 'sql, klass'
246
+ wrap_method :select_one, 'sql, klass'
247
+ wrap_method :count, 'sql, klass = nil'
248
+ wrap_method :delete, 'obj_or_oid, klass = nil'
249
+ wrap_method :prepare, 'sql'
250
+ wrap_method :query, 'sql'
251
+ wrap_method :exec, 'sql'
252
+
253
+ class << self
254
+ def create_db!(config)
255
+ adapter = Adapter.for_name(config[:adapter])
256
+ adapter.create_db(config[:database], config[:user], config[:password])
257
+ end
258
+ alias_method :create!, :create_db!
259
+
260
+ def drop_db!(config)
261
+ adapter = Adapter.for_name(config[:adapter])
262
+ adapter.drop_db(config[:database], config[:user], config[:password])
263
+ end
264
+ alias_method :drop!, :drop_db!
265
+ end
266
+ end
267
+
268
+ end
@@ -1,14 +1,17 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: meta.rb 248 2005-01-31 13:38:34Z gmosx $
4
-
5
- require 'og/backend'
3
+ # $Id: meta.rb 254 2005-02-10 12:44:05Z gmosx $
4
+ #--
5
+ # TODO:
6
+ # - precreate the meta sql statements as much as possible to
7
+ # avoid string interpolations.
8
+ #++
9
+
10
+ require 'og/adapter'
6
11
  require 'glue/inflector'
7
12
 
8
13
  class Og
9
14
 
10
- # = MetaUtils
11
- #
12
15
  # Some useful meta-language utilities.
13
16
 
14
17
  module MetaUtils # :nodoc: all
@@ -48,8 +51,6 @@ module MetaUtils # :nodoc: all
48
51
 
49
52
  end
50
53
 
51
- # = MetaLanguage
52
- #
53
54
  # Implements a meta-language for manipulating og-managed objects
54
55
  # and defining their relationships. The original idea comes
55
56
  # from the excellent ActiveRecord library.
@@ -125,11 +126,11 @@ module MetaLanguage
125
126
 
126
127
  module_eval %{
127
128
  def #{name}(extrasql = nil)
128
- Og.db.select_one("SELECT * FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
129
+ Og.db.select_one("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
129
130
  end
130
131
 
131
132
  def delete_#{name}(extrasql = nil)
132
- Og.db.exec("DELETE FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
133
+ Og.db.exec("DELETE FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
133
134
  end
134
135
  }
135
136
  end
@@ -162,11 +163,11 @@ module MetaLanguage
162
163
 
163
164
  module_eval %{
164
165
  def #{name}(extrasql = nil)
165
- Og.db.select("SELECT * FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
166
+ Og.db.select("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
166
167
  end
167
168
 
168
169
  def #{name}_count(extrasql = nil)
169
- Og.db.count("SELECT COUNT(*) FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
170
+ Og.db.count("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
170
171
  end
171
172
 
172
173
  def add_#{name_s}(obj, extra = nil)
@@ -175,7 +176,7 @@ module MetaLanguage
175
176
  end
176
177
 
177
178
  def delete_all_#{name}(extrasql = nil)
178
- Og.db.exec("DELETE FROM #{Backend.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
179
+ Og.db.exec("DELETE FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
179
180
  end
180
181
  }
181
182
  end
@@ -226,23 +227,23 @@ module MetaLanguage
226
227
 
227
228
  module_eval %{
228
229
  def #{list_o}(extrasql = nil)
229
- Og.db.select("SELECT d.* FROM #{Backend.table(klass)} AS d, #{Backend.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
230
+ Og.db.select("SELECT d.* FROM #{Og::Adapter.table(klass)} AS d, #{Og::Adapter.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
230
231
  end
231
232
 
232
233
  def #{list_o}_count(extrasql = nil)
233
- Og.db.select("SELECT COUNT(*) FROM #{Backend.table(klass)} AS d, #{Backend.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
234
+ Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} AS d, #{Og::Adapter.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
234
235
  end
235
236
 
236
237
  def add_#{prop_o}(obj, extra = nil)
237
- Og.db.exec("INSERT INTO #{Backend.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
238
+ Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
238
239
  end
239
240
 
240
241
  def delete_#{prop_o}(obj_or_oid, extra = nil)
241
- Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
242
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
242
243
  end
243
244
 
244
245
  def clear_#{list_o}
245
- Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key1=\#\@oid")
246
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\@oid")
246
247
  end
247
248
  }
248
249
 
@@ -250,23 +251,23 @@ module MetaLanguage
250
251
 
251
252
  klass.module_eval %{
252
253
  def #{list_m}(extrasql = nil)
253
- Og.db.select("SELECT s.* FROM #{Backend.table(self)} AS s, #{Backend.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
254
+ Og.db.select("SELECT s.* FROM #{Og::Adapter.table(self)} AS s, #{Og::Adapter.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
254
255
  end
255
256
 
256
257
  def #{list_m}_count(extrasql = nil)
257
- Og.db.select("SELECT COUNT(*) FROM #{Backend.table(self)} AS s, #{Backend.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
258
+ Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(self)} AS s, #{Og::Adapter.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
258
259
  end
259
260
 
260
261
  def add_#{prop_m}(obj, extra = nil)
261
- Og.db.exec("INSERT INTO #{Backend.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
262
+ Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
262
263
  end
263
264
 
264
265
  def delete_#{prop_m}(obj_or_oid, extra = nil)
265
- Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
266
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
266
267
  end
267
268
 
268
269
  def clear_#{list_m}
269
- Og.db.exec("DELETE FROM #{Backend.join_table(self, klass)} WHERE key2=\#\@oid")
270
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\@oid")
270
271
  end
271
272
  }
272
273
  end
@@ -3,10 +3,9 @@
3
3
  # (c) 2004-2005 Navel, all rights reserved.
4
4
  # $Id$
5
5
 
6
- require 'og'
6
+ require 'flexmock'
7
7
 
8
- require 'rubygems'
9
- require_gem 'flexmock'
8
+ require 'og'
10
9
 
11
10
  class Og
12
11
 
@@ -1,43 +1,40 @@
1
1
  #! /usr/bin/env ruby
2
2
  # vim:sw=2:ai
3
3
 
4
- # code:
5
4
  # * Thomas Quas <tquas@yahoo.com>
6
5
  # * George Moschovitis <gm@navel.gr>
7
- #
8
6
  # $Id$
9
7
 
10
8
  $LOAD_PATH.unshift 'lib'
11
9
 
12
- require "test/unit"
10
+ require 'test/unit'
13
11
  require 'glue/logger'
14
12
  require 'og/mock'
15
13
 
16
14
  $DBG = false
17
- $log = Logger.new( STDERR ) unless $log
18
15
 
19
16
  class Dummy
20
- prop_accessor :date
17
+ prop_accessor :date, Time
21
18
  attr_reader :call_stack
22
19
 
23
20
  def og_pre_insert( oid )
24
- @call_stack << "pre_insert"
21
+ @call_stack << 'pre_insert'
25
22
  end
26
23
 
27
24
  def og_post_insert( oid )
28
- @call_stack << "post_insert"
25
+ @call_stack << 'post_insert'
29
26
  end
30
27
 
31
28
  def og_pre_update( oid )
32
- @call_stack << "pre_update"
29
+ @call_stack << 'pre_update'
33
30
  end
34
31
 
35
32
  def og_post_update( oid )
36
- @call_stack << "post_update"
33
+ @call_stack << 'post_update'
37
34
  end
38
35
 
39
36
  def self.og_pre_delete( conn, oid )
40
- raise "undeletable"
37
+ raise 'undeletable'
41
38
  end
42
39
 
43
40
  def initialize
@@ -51,8 +48,8 @@ class TC_CallbackTest < ::Test::Unit::TestCase
51
48
  obj = Dummy.new
52
49
  obj.save!
53
50
 
54
- assert( obj.call_stack.shift == "pre_insert" )
55
- assert( obj.call_stack.shift == "post_insert" )
51
+ assert( obj.call_stack.shift == 'pre_insert' )
52
+ assert( obj.call_stack.shift == 'post_insert' )
56
53
  assert( obj.call_stack.empty? )
57
54
  end
58
55
 
@@ -75,7 +72,7 @@ class TC_CallbackTest < ::Test::Unit::TestCase
75
72
  obj.call_stack.shift
76
73
  obj.call_stack.shift
77
74
 
78
- assert_raise( RuntimeError, "undeletable" ) { obj.delete! }
75
+ assert_raise( RuntimeError, 'undeletable' ) { obj.delete! }
79
76
  end
80
77
 
81
78
  def setup
@@ -83,25 +80,25 @@ class TC_CallbackTest < ::Test::Unit::TestCase
83
80
 
84
81
  if psql
85
82
  config = {
86
- :backend => "psql",
87
- :address => "localhost",
88
- :database => "test",
89
- :user => "postgres",
90
- :password => "navelrulez",
83
+ :adapter => 'psql',
84
+ # :address => 'localhost',
85
+ :database => 'test',
86
+ :user => 'postgres',
87
+ :password => 'navelrulez',
91
88
  :connection_count => 1
92
89
  }
93
90
  else
94
91
  config = {
95
- :backend => "mysql",
96
- :address => "localhost",
97
- :database => "test",
98
- :user => "root",
99
- :password => "navelrulez",
92
+ :adapter => 'mysql',
93
+ # :address => 'localhost',
94
+ :database => 'test',
95
+ :user => 'root',
96
+ :password => 'navelrulez',
100
97
  :connection_count => 1
101
98
  }
102
99
  end
103
- Og::Database.drop_db!( config )
104
- $og = Og::Database.new( config )
100
+ Og::Database.drop_db!(config)
101
+ $og = Og::Database.new(config)
105
102
  $og.get_connection()
106
103
  end
107
104
  end