og 0.8.0 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,7 @@
4
4
  # * Elias Karakoulakis <ekarak@ktismata.com>
5
5
  #
6
6
  # (c) 2004 Navel, all rights reserved.
7
- # $Id: string.rb 165 2004-11-18 12:04:04Z gmosx $
7
+ # $Id: string.rb 202 2005-01-17 10:44:13Z gmosx $
8
8
 
9
9
  require "uri"
10
10
 
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: time.rb 167 2004-11-23 14:03:10Z gmosx $
5
+ # $Id: time.rb 202 2005-01-17 10:44:13Z gmosx $
6
6
 
7
7
  require "time.rb"
8
8
 
@@ -216,7 +216,7 @@ module Validation
216
216
 
217
217
  for name in params
218
218
  confirm_name = "#{name}#{c[:postfix]}"
219
- attr_accessor :"#{confirm_name}"
219
+ eval "attr_accessor :#{confirm_name}"
220
220
 
221
221
  code = %{
222
222
  if obj.#{confirm_name}.nil? or (obj.#{confirm_name} != obj.#{name})
data/lib/og.rb CHANGED
@@ -1,18 +1,15 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: og.rb 197 2004-12-21 13:50:17Z gmosx $
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: og.rb 248 2005-01-31 13:38:34Z gmosx $
6
4
 
7
5
  require 'glue/logger'
6
+ require 'glue/attribute'
8
7
  require 'glue/property'
9
8
  require 'glue/array'
10
9
  require 'glue/hash'
11
10
  require 'glue/time'
12
11
  require 'glue/pool'
13
12
 
14
- # = Og
15
- #
16
13
  # Og (ObjectGraph) is an efficient, yet simple Object-Relational
17
14
  # mapping library.
18
15
  #
@@ -36,7 +33,7 @@ require 'glue/pool'
36
33
  # + Works safely as part of distributed application.
37
34
  # + Simple implementation.
38
35
  #
39
- # === Meta language
36
+ # == Meta language
40
37
  #
41
38
  # primary_key :pid (NOT IMPLEMENTED)
42
39
  # name_key :name (NOT IMPLEMENTED)
@@ -45,7 +42,7 @@ require 'glue/pool'
45
42
  # many_to_many Role, :roles
46
43
  # sql_index :pid
47
44
  #
48
- # === Design
45
+ # == Design
49
46
  #
50
47
  # Keep the main classes backend agnostic.
51
48
  #--
@@ -69,7 +66,7 @@ require 'glue/pool'
69
66
  # The og.xxx methods are more flexible and allow you to use
70
67
  # multiple databases for example.
71
68
  #
72
- # === Managed Objects Lifecycle Callbacks
69
+ # == Managed Objects Lifecycle Callbacks
73
70
  #
74
71
  # * og_pre_insert
75
72
  # * og_post_insert
@@ -82,53 +79,58 @@ require 'glue/pool'
82
79
  # A class level callback is used for delete because typically you call
83
80
  # delete with an oid and not an object to avoid a deserialization.
84
81
  #
85
- # === Future
82
+ # == Future
86
83
  #
87
84
  # * Support prepared statements (pgsql)
88
85
  # * Support stored procedures (pgsql)
89
86
  # * Support caching.
90
87
  # * Deserialize to OpenStruct.
91
88
  # * Better documentation.
92
- #
89
+
93
90
  class Og
94
- class << self
95
- # If true, only allow reading from the database. Usefull
96
- # for maintainance.
97
- attr_accessor :read_only_mode
98
-
99
- # If true, the library automatically 'enchants' managed classes.
100
- # In enchant mode, special db aware methods are added to
101
- # managed classes and instances.
102
- attr_accessor :enchant_managed_classes
103
-
104
- # If true, use Ruby's advanced introspection capabilities to
105
- # automatically manage classes tha define properties.
106
- attr_accessor :auto_manage_classes
107
91
 
108
- # If true, automatically include the Og meta-language into Module.
109
- attr_accessor :include_meta_language
110
-
111
- # Attach the following prefix to all generated SQL table names.
112
- # Usefull on hosting scenarios where you have to run multiple
113
- # web applications/sites on a single database.
114
- attr_accessor :table_prefix
115
-
116
- # The active database. Og allows you to access multiple
117
- # databases from a single application.
118
- attr_accessor :db
119
-
120
- def use(db)
121
- @db = db
122
- @db.get_connection
123
- end
124
- end
92
+ # If true, only allow reading from the database. Usefull
93
+ # for maintainance.
94
+
95
+ cattr_accessor :read_only_mode, false
96
+
97
+ # If true, the library automatically 'enchants' managed classes.
98
+ # In enchant mode, special db aware methods are added to
99
+ # managed classes and instances.
100
+
101
+ cattr_accessor :enchant_managed_classes, true
102
+
103
+ # If true, use Ruby's advanced introspection capabilities to
104
+ # automatically manage classes tha define properties.
105
+
106
+ cattr_accessor :auto_manage_classes, true
107
+
108
+ # If true, automatically include the Og meta-language into Module.
109
+ #
110
+ # By default this is FALSE, to avoid polution of the Module object.
111
+ # However if you include a prop_accessor or a managed Mixin in your
112
+ # object MetaLanguage gets automatically extended in the class.
113
+
114
+ cattr_accessor :include_meta_language, true
115
+
116
+ # Attach the following prefix to all generated SQL table names.
117
+ # Usefull on hosting scenarios where you have to run multiple
118
+ # web applications/sites on a single database.
125
119
 
126
- # set default options:
127
- self.read_only_mode = false
128
- self.enchant_managed_classes = true
129
- self.auto_manage_classes = true
130
- self.include_meta_language = true
131
- self.table_prefix = nil
120
+ cattr_accessor :table_prefix, nil
121
+
122
+ # The active database. Og allows you to access multiple
123
+ # databases from a single application.
124
+
125
+ cattr_accessor :db
126
+
127
+ # Set the active database.
128
+
129
+ def self.use(db)
130
+ @@db = db
131
+ @@db.get_connection
132
+ end
133
+
132
134
  end
133
135
 
134
136
  # gmosx: leave this here.
@@ -137,22 +139,18 @@ require 'og/meta'
137
139
 
138
140
  class Og
139
141
 
140
- # = Unmanageable
141
- #
142
142
  # Marker module. If included this in a class, the Og automanager
143
143
  # ignores this class.
144
- #
144
+
145
145
  module Unmanageable; end
146
146
 
147
- # = Database
148
- #
149
147
  # Encapsulates an Og Database.
150
- #
148
+
151
149
  class Database
152
150
  include Og::Enchant
153
151
 
154
152
  # Managed class metadata
155
- #
153
+
156
154
  class ManagedClassMeta
157
155
  # The managed class.
158
156
  attr_accessor :klass
@@ -167,16 +165,19 @@ class Database
167
165
  end
168
166
 
169
167
  # hash of configuration options.
168
+
170
169
  attr_accessor :config
171
170
 
172
171
  # Pool of connections to the backend.
172
+
173
173
  attr_accessor :connection_pool
174
174
 
175
175
  # Managed classes.
176
+
176
177
  attr_accessor :managed_classes
177
178
 
178
179
  # Initialize the database interface.
179
- #
180
+
180
181
  def initialize(config)
181
182
  @config = config
182
183
 
@@ -199,7 +200,7 @@ class Database
199
200
 
200
201
  # gmosx, FIXME: this automanage code is not elegant and slow
201
202
  # should probably recode this, along with glue/property.rb
202
- #
203
+
203
204
  if Og.auto_manage_classes
204
205
  # automatically manage classes with properties and metadata.
205
206
  # gmosx: Any idea how to optimize this?
@@ -219,7 +220,7 @@ class Database
219
220
  end
220
221
 
221
222
  # Shutdown the database interface.
222
- #
223
+
223
224
  def shutdown
224
225
  for con in @connection_pool
225
226
  con.close()
@@ -229,7 +230,7 @@ class Database
229
230
 
230
231
  # Get a connection from the pool to access the database.
231
232
  # Stores the connection in a thread-local variable.
232
- #
233
+
233
234
  def get_connection
234
235
  thread = Thread.current
235
236
 
@@ -243,7 +244,7 @@ class Database
243
244
  alias_method :connection, :get_connection
244
245
 
245
246
  # Restore an unused connection to the pool.
246
- #
247
+
247
248
  def put_connection
248
249
  thread = Thread.current
249
250
 
@@ -254,7 +255,7 @@ class Database
254
255
  end
255
256
 
256
257
  # Utility method, automatically restores a connection to the pool.
257
- #
258
+
258
259
  def connect(deserialize = nil, &block)
259
260
  result = nil
260
261
 
@@ -275,7 +276,7 @@ class Database
275
276
 
276
277
 
277
278
  # Register a standard Ruby class as managed.
278
- #
279
+
279
280
  def manage(klass)
280
281
  return if managed?(klass) or klass.ancestors.include?(Og::Unmanageable)
281
282
 
@@ -289,7 +290,7 @@ class Database
289
290
  end
290
291
 
291
292
  # Helper method to set multiple managed classes.
292
- #
293
+
293
294
  def manage_classes(*klasses)
294
295
  for klass in klasses
295
296
  manage(klass)
@@ -297,7 +298,7 @@ class Database
297
298
  end
298
299
 
299
300
  # Stop managing a Ruby class
300
- #
301
+
301
302
  def unmanage(klass)
302
303
  @managed_classes.delete(klass)
303
304
  end
@@ -309,7 +310,7 @@ class Database
309
310
  end
310
311
 
311
312
  # Add standard og functionality to the class
312
- #
313
+
313
314
  def convert(klass)
314
315
  # Grab backend class
315
316
  backend = @config[:backend]
@@ -393,4 +394,4 @@ class Database
393
394
  end
394
395
  end
395
396
 
396
- end # namespace
397
+ end
@@ -2,7 +2,7 @@
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  #
4
4
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: backend.rb 197 2004-12-21 13:50:17Z gmosx $
5
+ # $Id: backend.rb 202 2005-01-17 10:44:13Z gmosx $
6
6
 
7
7
  require "yaml"
8
8
 
@@ -1,39 +1,35 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
2
  # * Elias Athanasopoulos <elathan@navel.gr>
4
- #
5
- # (c) 2004 Navel, all rights reserved.
6
- # $Id: mysql.rb 194 2004-12-20 20:23:57Z gmosx $
3
+ # (c) 2004-2005 Navel, all rights reserved.
4
+ # $Id: mysql.rb 248 2005-01-31 13:38:34Z gmosx $
7
5
 
8
- require "mysql"
6
+ require 'mysql'
9
7
 
10
- require "og/backend"
8
+ require 'og/backend'
11
9
 
12
10
  class Og
13
11
 
14
- # = MysqlBackend
15
- #
16
12
  # Implements a MySQL powered backend.
17
- #
13
+
18
14
  class MysqlBackend < Og::Backend
19
15
 
20
16
  # A mapping between Ruby and SQL types.
21
- #
17
+
22
18
  TYPEMAP = {
23
- Integer => "integer",
24
- Fixnum => "integer",
25
- Float => "float",
26
- String => "text",
27
- Time => "timestamp",
28
- Date => "date",
29
- TrueClass => "boolean",
30
- Object => "text",
31
- Array => "text",
32
- Hash => "text"
19
+ Integer => 'integer',
20
+ Fixnum => 'integer',
21
+ Float => 'float',
22
+ String => 'text',
23
+ Time => 'timestamp',
24
+ Date => 'date',
25
+ TrueClass => 'tinyint',
26
+ Object => 'text',
27
+ Array => 'text',
28
+ Hash => 'text'
33
29
  }
34
30
 
35
31
  # Intitialize the connection to the RDBMS.
36
- #
32
+
37
33
  def initialize(config)
38
34
  begin
39
35
  @conn = Mysql.connect(config[:address], config[:user],
@@ -53,7 +49,7 @@ class MysqlBackend < Og::Backend
53
49
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54
50
 
55
51
  # Escape an SQL string
56
- #
52
+
57
53
  def self.escape(str)
58
54
  return nil unless str
59
55
  return Mysql.quote(str)
@@ -61,7 +57,7 @@ class MysqlBackend < Og::Backend
61
57
 
62
58
  # Convert a ruby time to an sql timestamp.
63
59
  # TODO: Optimize this
64
- #
60
+
65
61
  def self.timestamp(time = Time.now)
66
62
  return nil unless time
67
63
  return time.strftime("%Y%m%d%H%M%S")
@@ -69,7 +65,7 @@ class MysqlBackend < Og::Backend
69
65
 
70
66
  # Output YYY-mm-dd
71
67
  # TODO: Optimize this
72
- #
68
+
73
69
  def self.date(date)
74
70
  return nil unless date
75
71
  return "#{date.year}-#{date.month}-#{date.mday}"
@@ -77,14 +73,14 @@ class MysqlBackend < Og::Backend
77
73
 
78
74
  # Parse sql datetime
79
75
  # TODO: Optimize this
80
- #
76
+
81
77
  def self.parse_timestamp(str)
82
78
  return Time.parse(str)
83
79
  end
84
80
 
85
81
  # Input YYYY-mm-dd
86
82
  # TODO: Optimize this
87
- #
83
+
88
84
  def self.parse_date(str)
89
85
  return nil unless str
90
86
  return Date.strptime(str)
@@ -96,7 +92,7 @@ class MysqlBackend < Og::Backend
96
92
  # portable.
97
93
  #
98
94
  # FIXME: add extra handling for float.
99
- #
95
+
100
96
  def self.write_prop(p)
101
97
  if p.klass.ancestors.include?(Integer)
102
98
  return "#\{@#{p.symbol} || 'NULL'\}"
@@ -109,7 +105,7 @@ class MysqlBackend < Og::Backend
109
105
  elsif p.klass.ancestors.include?(Date)
110
106
  return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.date(@#{p.symbol})\}'" : 'NULL'\}|
111
107
  elsif p.klass.ancestors.include?(TrueClass)
112
- return "#\{@#{p.symbol} || 'NULL'\}"
108
+ return "#\{@#{p.symbol} ? 1 : 0 \}"
113
109
  else
114
110
  return %|#\{@#{p.symbol} ? "'#\{Og::MysqlBackend.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
115
111
  end
@@ -117,7 +113,7 @@ class MysqlBackend < Og::Backend
117
113
 
118
114
  # Return an evaluator for reading the property.
119
115
  # No need to optimize this, used only to precalculate code.
120
- #
116
+
121
117
  def self.read_prop(p, idx)
122
118
  if p.klass.ancestors.include?(Integer)
123
119
  return "res[#{idx}].to_i()"
@@ -130,7 +126,7 @@ class MysqlBackend < Og::Backend
130
126
  elsif p.klass.ancestors.include?(Date)
131
127
  return "Og::MysqlBackend.parse_date(res[#{idx}])"
132
128
  elsif p.klass.ancestors.include?(TrueClass)
133
- return "('true' == res[#{idx}])"
129
+ return "('0' != res[#{idx}])"
134
130
  else
135
131
  return "YAML::load(res[#{idx}])"
136
132
  end
@@ -139,14 +135,14 @@ class MysqlBackend < Og::Backend
139
135
  # Returns the props that will be included in the insert query.
140
136
  # The oid property is rejected because it is mapped to an
141
137
  # AUTO_INCREMENT column.
142
- #
138
+
143
139
  def self.props_for_insert(klass)
144
140
  klass.__props.reject { |p| :oid == p.symbol }
145
141
  end
146
142
 
147
- # Returns the code that actually inserts the object into the
143
+ # Returns the code that actually inserts the object into the
148
144
  # database. Returns the code as String.
149
- #
145
+
150
146
  def self.insert_code(klass, sql, pre_cb, post_cb)
151
147
  %{
152
148
  #{pre_cb}
@@ -158,7 +154,7 @@ class MysqlBackend < Og::Backend
158
154
 
159
155
  # generate the mapping of the database fields to the
160
156
  # object properties.
161
- #
157
+
162
158
  def self.calc_field_index(klass, og)
163
159
  res = og.query "SELECT * FROM #{klass::DBTABLE} LIMIT 1"
164
160
  meta = og.managed_classes[klass]
@@ -168,8 +164,8 @@ class MysqlBackend < Og::Backend
168
164
  end
169
165
  end
170
166
 
171
- # Generate the property for oid
172
- #
167
+ # Generate the property for oid.
168
+
173
169
  def self.eval_og_oid(klass)
174
170
  klass.class_eval %{
175
171
  prop_accessor :oid, Fixnum, :sql => "integer AUTO_INCREMENT PRIMARY KEY"
@@ -181,28 +177,28 @@ class MysqlBackend < Og::Backend
181
177
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
182
178
 
183
179
  # Create the database.
184
- #
180
+
185
181
  def self.create_db(database, user = nil, password = nil)
186
182
  Logger.info "Creating database '#{database}'."
187
183
  `mysqladmin -f --user=#{user} --password=#{password} create #{database}`
188
184
  end
189
185
 
190
186
  # Drop the database.
191
- #
187
+
192
188
  def self.drop_db(database, user = nil, password = nil)
193
189
  Logger.info "Dropping database '#{database}'."
194
190
  `mysqladmin -f --user=#{user} --password=#{password} drop #{database}`
195
191
  end
196
192
 
197
193
  # Execute an SQL query and return the result
198
- #
194
+
199
195
  def query(sql)
200
196
  Logger.debug sql if $DBG
201
197
  return @conn.query(sql)
202
198
  end
203
199
 
204
200
  # Execute an SQL query, no result returned.
205
- #
201
+
206
202
  def exec(sql)
207
203
  Logger.debug sql if $DBG
208
204
  @conn.query(sql)
@@ -210,7 +206,7 @@ class MysqlBackend < Og::Backend
210
206
 
211
207
  # Execute an SQL query and return the result. Wrapped in a rescue
212
208
  # block.
213
- #
209
+
214
210
  def safe_query(sql)
215
211
  Logger.debug sql if $DBG
216
212
  begin
@@ -224,7 +220,7 @@ class MysqlBackend < Og::Backend
224
220
 
225
221
  # Execute an SQL query, no result returned. Wrapped in a rescue
226
222
  # block.
227
- #
223
+
228
224
  def safe_exec(sql)
229
225
  Logger.debug sql if $DBG
230
226
  begin
@@ -236,25 +232,25 @@ class MysqlBackend < Og::Backend
236
232
  end
237
233
 
238
234
  # Check if it is a valid resultset.
239
- #
235
+
240
236
  def valid?(res)
241
237
  return !(res.nil? or 0 == res.num_rows)
242
238
  end
243
239
 
244
240
  # Start a new transaction.
245
- #
241
+
246
242
  def start
247
243
  # no transaction support
248
244
  end
249
245
 
250
246
  # Commit a transaction.
251
- #
247
+
252
248
  def commit
253
249
  # no transaction support
254
250
  end
255
251
 
256
252
  # Rollback transaction.
257
- #
253
+
258
254
  def rollback
259
255
  # no transaction support
260
256
  end
@@ -262,7 +258,7 @@ class MysqlBackend < Og::Backend
262
258
  # Create the managed object table. The properties of the
263
259
  # object are mapped to the table columns. Additional sql relations
264
260
  # and constrains are created (indicices, sequences, etc).
265
- #
261
+
266
262
  def create_table(klass)
267
263
  fields = create_fields(klass, TYPEMAP)
268
264
 
@@ -328,7 +324,7 @@ class MysqlBackend < Og::Backend
328
324
  end
329
325
 
330
326
  # Deserialize one row of the resultset.
331
- #
327
+
332
328
  def deserialize_one(res, klass)
333
329
  return nil unless valid?(res)
334
330
 
@@ -343,9 +339,9 @@ class MysqlBackend < Og::Backend
343
339
  end
344
340
 
345
341
  # Deserialize all rows of the resultset.
346
- #
342
+
347
343
  def deserialize_all(res, klass)
348
- return nil unless valid?(res)
344
+ return [] unless valid?(res)
349
345
 
350
346
  entities = []
351
347
 
@@ -364,11 +360,11 @@ class MysqlBackend < Og::Backend
364
360
  end
365
361
 
366
362
  # Return a single integer value from the resultset.
367
- #
363
+
368
364
  def get_int(res, idx = 0)
369
365
  return res.fetch_row[idx].to_i
370
366
  end
371
367
 
372
368
  end
373
369
 
374
- end # module
370
+ end