og 0.9.5 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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