og 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: mysql.rb 266 2005-02-28 14:50:48Z gmosx $
3
+ # $Id: mysql.rb 270 2005-03-07 17:52:16Z gmosx $
4
4
 
5
5
  require 'mysql'
6
6
 
@@ -19,6 +19,7 @@ class MysqlAdapter < Adapter
19
19
  def initialize
20
20
  super
21
21
  @typemap.update(TrueClass => 'tinyint')
22
+ @typecast.update(TrueClass => "#\{:s: ? \"1\" : 'NULL' \}")
22
23
  end
23
24
 
24
25
  def self.escape(str)
@@ -118,6 +119,43 @@ class MysqlAdapter < Adapter
118
119
  res.free if res
119
120
  end
120
121
 
122
+ def create_fields(klass)
123
+ fields = []
124
+
125
+ klass.__props.each do |p|
126
+ klass.sql_index(p.symbol) if p.meta[:sql_index]
127
+
128
+ field = "#{p.symbol}"
129
+
130
+ if p.meta and p.meta[:sql]
131
+ field << " #{p.meta[:sql]}"
132
+ else
133
+ field << " #{@typemap[p.klass]}"
134
+
135
+ if p.meta
136
+ # set default value (gmosx: not that useful in the
137
+ # current implementation).
138
+ if default = p.meta[:default]
139
+ field << " DEFAULT #{default.inspect} NOT NULL"
140
+ end
141
+
142
+ # set unique
143
+ # FIXME: correctly handle UNIQUE constrain.
144
+ # field << " UNIQUE" if p.meta[:unique]
145
+
146
+ # attach extra sql
147
+ if extra_sql = p.meta[:extra_sql]
148
+ field << " #{extra_sql}"
149
+ end
150
+ end
151
+ end
152
+
153
+ fields << field
154
+ end
155
+
156
+ return fields
157
+ end
158
+
121
159
  def create_table(klass, db)
122
160
  conn = db.get_connection
123
161
 
@@ -165,11 +203,11 @@ class MysqlAdapter < Adapter
165
203
  if klass.__meta and joins = klass.__meta[:sql_join]
166
204
  for data in joins
167
205
  # the class to join to and some options.
168
- join_class, options = *data
206
+ join_name, join_class, options = *data
169
207
 
170
208
  # gmosx: dont use DBTABLE here, perhaps the join class
171
209
  # is not managed yet.
172
- join_table = "#{self.class.join_table(klass, join_class)}"
210
+ join_table = "#{self.class.join_table(klass, join_class, join_name)}"
173
211
  join_src = "#{self.class.encode(klass)}_oid"
174
212
  join_dst = "#{self.class.encode(join_class)}_oid"
175
213
  begin
@@ -1,7 +1,7 @@
1
1
  # * Matt Bowen <matt.bowen@farweststeel.com>
2
2
  # * George Moschovitis <gm@navel.gr>
3
3
  # (c) 2004-2005 Navel, all rights reserved.
4
- # $Id: oracle.rb 266 2005-02-28 14:50:48Z gmosx $
4
+ # $Id: oracle.rb 270 2005-03-07 17:52:16Z gmosx $
5
5
 
6
6
  require 'oracle'
7
7
 
@@ -28,6 +28,7 @@ class OracleAdapter < Adapter
28
28
  Array => 'varchar2(1024)',
29
29
  Hash => 'varchar2(1024)'
30
30
  )
31
+ @typecast.update(TrueClass => "#\{:s: ? \"1\" : 'NULL' \}")
31
32
  end
32
33
 
33
34
  def self.timestamp(time = Time.now)
@@ -190,11 +191,11 @@ class OracleAdapter < Adapter
190
191
  if klass.__meta and joins = klass.__meta[:sql_join]
191
192
  for data in joins
192
193
  # the class to join to and some options.
193
- join_class, options = *data
194
+ join_name, join_class, options = *data
194
195
 
195
196
  # gmosx: dont use DBTABLE here, perhaps the join class
196
197
  # is not managed yet.
197
- join_table = "#{self.class.join_table(klass, join_class)}"
198
+ join_table = "#{self.class.join_table(klass, join_class, join_name)}"
198
199
  join_src = "#{self.class.encode(klass)}_oid"
199
200
  join_dst = "#{self.class.encode(join_class)}_oid"
200
201
  begin
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: psql.rb 266 2005-02-28 14:50:48Z gmosx $
3
+ # $Id: psql.rb 270 2005-03-07 17:52:16Z gmosx $
4
4
 
5
5
  require 'postgres'
6
6
 
@@ -137,11 +137,11 @@ class PsqlAdapter < Adapter
137
137
  if klass.__meta and joins = klass.__meta[:sql_join]
138
138
  for data in joins
139
139
  # the class to join to and some options.
140
- join_class, options = *data
140
+ join_name, join_class, options = *data
141
141
 
142
142
  # gmosx: dont use DBTABLE here, perhaps the join class
143
143
  # is not managed yet.
144
- join_table = "#{self.class.join_table(klass, join_class)}"
144
+ join_table = "#{self.class.join_table(klass, join_class, join_name)}"
145
145
  join_src = "#{self.class.encode(klass)}_oid"
146
146
  join_dst = "#{self.class.encode(join_class)}_oid"
147
147
  begin
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: sqlite.rb 263 2005-02-23 13:45:08Z gmosx $
3
+ # $Id: sqlite.rb 270 2005-03-07 17:52:16Z gmosx $
4
4
 
5
5
  require 'sqlite3'
6
6
  require 'fileutils'
@@ -142,11 +142,11 @@ class SqliteAdapter < Adapter
142
142
  if klass.__meta and joins = klass.__meta[:sql_join]
143
143
  for data in joins
144
144
  # the class to join to and some options.
145
- join_class, options = *data
145
+ join_name, join_class, options = *data
146
146
 
147
147
  # gmosx: dont use DBTABLE here, perhaps the join class
148
148
  # is not managed yet.
149
- join_table = "#{self.class.join_table(klass, join_class)}"
149
+ join_table = "#{self.class.join_table(klass, join_class, join_name)}"
150
150
  join_src = "#{self.class.encode(klass)}_oid"
151
151
  join_dst = "#{self.class.encode(join_class)}_oid"
152
152
  begin
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: connection.rb 265 2005-02-24 08:46:54Z gmosx $
3
+ # $Id: connection.rb 270 2005-03-07 17:52:16Z gmosx $
4
4
 
5
5
  module Og;
6
6
 
@@ -270,6 +270,10 @@ class Connection
270
270
  #
271
271
  # obj_or_oid = Object or oid to delete.
272
272
  # klass = Class of object (can be nil if an object is passed)
273
+ #
274
+ #--
275
+ # TODO: pre evaluate for symmetry to the other methods
276
+ #++
273
277
 
274
278
  def delete(obj_or_oid, klass = nil, cascade = true)
275
279
  oid = obj_or_oid.to_i
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: database.rb 265 2005-02-24 08:46:54Z gmosx $
3
+ # $Id: database.rb 270 2005-03-07 17:52:16Z gmosx $
4
4
 
5
5
  require 'glue/logger'
6
6
  require 'glue/attribute'
@@ -12,6 +12,7 @@ require 'glue/pool'
12
12
 
13
13
  require 'og/enchant'
14
14
  require 'og/meta'
15
+ require 'og/observer'
15
16
 
16
17
  module Og
17
18
 
@@ -68,7 +69,6 @@ class Database
68
69
  @managed_classes = N::SafeHash.new
69
70
 
70
71
  @config[:connection_count].times do
71
- # @connection_pool << Og::Connection.new(self)
72
72
  @connection_pool << @adapter.new_connection(self)
73
73
  end
74
74
 
@@ -148,11 +148,10 @@ class Database
148
148
  end
149
149
  alias_method :open, :connect
150
150
 
151
-
152
151
  # Register a standard Ruby class as managed.
153
152
 
154
153
  def manage(klass)
155
- return if managed?(klass) or klass.ancestors.include?(Og::Unmanageable)
154
+ return if managed?(klass) or klass.ancestors.include?(Unmanageable)
156
155
 
157
156
  @managed_classes[klass] = ManagedClassMeta.new(klass)
158
157
 
@@ -194,22 +193,31 @@ class Database
194
193
  klass.class_eval %{
195
194
  DBTABLE = "#{Adapter.table(klass)}"
196
195
  DBSEQ = "#{Adapter.table(klass)}_oid_seq"
197
-
198
- def to_i()
196
+
197
+ cattr_accessor :og_db
198
+
199
+ def to_i
199
200
  @oid
200
201
  end
201
202
  }
202
203
 
204
+ # Set the adapter.
205
+
206
+ klass.og_db = self
207
+
208
+ # Add observer support.
209
+
210
+ klass.extend(Observable)
211
+
203
212
  # Create the schema for this class if not available.
213
+
204
214
  @adapter.create_table(klass, self) if Og.create_schema
205
215
 
206
- # Precompile some code that gets executed all the time.
207
- # Deletion code is not precompiled, because it is not used
208
- # as frequently.
216
+ # @adapter.eval_og_insert(klass, self)
217
+ # @adapter.eval_og_update(klass, self)
218
+ # @adapter.eval_og_read(klass, self)
209
219
 
210
- @adapter.eval_og_insert(klass, self)
211
- @adapter.eval_og_update(klass, self)
212
- @adapter.eval_og_read(klass, self)
220
+ @adapter.eval_lifecycle_methods(klass, self)
213
221
  end
214
222
 
215
223
  # Automatically wrap connection methods.
@@ -251,17 +259,23 @@ class Database
251
259
  wrap_method :exec, 'sql'
252
260
 
253
261
  class << self
262
+
263
+ # Create a new database.
264
+
254
265
  def create_db!(config)
255
266
  adapter = Adapter.for_name(config[:adapter])
256
267
  adapter.create_db(config[:database], config[:user], config[:password])
257
268
  end
258
269
  alias_method :create!, :create_db!
259
270
 
271
+ # Drop an existing database.
272
+
260
273
  def drop_db!(config)
261
274
  adapter = Adapter.for_name(config[:adapter])
262
275
  adapter.drop_db(config[:database], config[:user], config[:password])
263
276
  end
264
277
  alias_method :drop!, :drop_db!
278
+
265
279
  end
266
280
  end
267
281
 
@@ -10,54 +10,65 @@ module Enchant
10
10
  # to the class and its instances.
11
11
 
12
12
  def enchant(klass)
13
- klass.module_eval <<-"end_eval", __FILE__, __LINE__
13
+
14
+ # Generate standard methods.
15
+
16
+ klass.module_eval %{
14
17
  def self.create(*params, &block)
15
18
  obj = #{klass}.new(*params, &block)
16
19
  obj.save!
17
20
  end
18
21
 
19
22
  def self.save(obj)
20
- Og.db << obj
23
+ @@og_db << obj
21
24
  end
22
25
 
23
26
  def self.load(oid_or_name)
24
- Og.db.load(oid_or_name, #{klass})
27
+ @@og_db.load(oid_or_name, #{klass})
25
28
  end
26
29
 
27
30
  def self.get(oid_or_name)
28
- Og.db.load(oid_or_name, #{klass})
31
+ @@og_db.load(oid_or_name, #{klass})
29
32
  end
30
33
 
31
34
  def self.[](oid_or_name)
32
- Og.db.load(oid_or_name, #{klass})
35
+ @@og_db.load(oid_or_name, #{klass})
33
36
  end
34
37
 
35
38
  def self.load_all(extra_sql = nil)
36
- Og.db.load_all(#{klass}, extra_sql)
39
+ @@og_db.load_all(#{klass}, extra_sql)
37
40
  end
38
41
 
39
42
  def self.all(extra_sql = nil)
40
- Og.db.load_all(#{klass}, extra_sql)
43
+ @@og_db.load_all(#{klass}, extra_sql)
41
44
  end
42
45
 
43
46
  def self.count(sql = "SELECT COUNT(*) FROM #{klass::DBTABLE}")
44
- Og.db.count(sql, #{klass})
47
+ @@og_db.count(sql, #{klass})
45
48
  end
46
49
 
47
50
  def self.select(sql)
48
- Og.db.select(sql, #{klass})
51
+ @@og_db.select(sql, #{klass})
52
+ end
53
+
54
+ def self.find(sql)
55
+ @@og_db.select(sql, #{klass})
49
56
  end
50
57
 
51
58
  def self.select_one(sql)
52
- Og.db.select_one(sql, #{klass})
59
+ @@og_db.select_one(sql, #{klass})
60
+ end
61
+
62
+ def self.find_one(sql)
63
+ @@og_db.select_one(sql, #{klass})
53
64
  end
54
65
 
55
66
  def self.one(sql)
56
- Og.db.select_one(sql, #{klass})
67
+ @@og_db.select_one(sql, #{klass})
57
68
  end
58
69
 
59
70
  def self.delete(obj_or_oid)
60
- Og.db.delete(obj_or_oid, #{klass})
71
+ @@og_db.delete(obj_or_oid, #{klass})
61
72
  end
62
73
 
63
74
  def self.properties_and_relations
@@ -70,20 +81,43 @@ module Enchant
70
81
  include Enumerable
71
82
 
72
83
  def save
73
- Og.db << self
84
+ @@og_db << self
74
85
  return self
75
86
  end
76
87
  alias_method :save!, :save
77
88
 
78
89
  def update_properties(updatesql)
79
- Og.db.pupdate(updatesql, self.oid, #{klass})
90
+ @@og_db.pupdate(updatesql, self.oid, #{klass})
80
91
  end
81
92
  alias_method :pupdate!, :update_properties
82
93
 
83
94
  def delete!
84
- Og.db.delete(@oid, #{klass})
95
+ @@og_db.delete(@oid, #{klass})
85
96
  end
86
- end_eval
97
+ }
98
+
99
+ # Generate finder methods.
100
+
101
+ code = ''
102
+
103
+ for p in klass.__props
104
+ code << %{
105
+ def self.find_by_#{p.name}(val, operator = '=', extra_sql = nil)
106
+ }
107
+
108
+ val = klass.og_db.adapter.typecast[p.klass].gsub(/\:s\:/, 'val')
109
+
110
+ if p.meta[:unique]
111
+ code << %{@@og_db.select_one("#{p.name}\#\{operator\}#{val} \#\{extra_sql\}", #{klass})}
112
+ else
113
+ code << %{@@og_db.select("#{p.name}\#\{operator\}#{val} \#\{extra_sql\}", #{klass})}
114
+ end
115
+ code << %{
116
+ end;
117
+ }
118
+ end
119
+
120
+ klass.module_eval(code)
87
121
  end
88
122
 
89
123
  end
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: meta.rb 266 2005-02-28 14:50:48Z gmosx $
3
+ # $Id: meta.rb 270 2005-03-07 17:52:16Z gmosx $
4
4
  #--
5
5
  # TODO:
6
6
  # - precreate the meta sql statements as much as possible to
@@ -135,7 +135,7 @@ module MetaLanguage
135
135
  # linkback is the property of the child object that 'links back'
136
136
  # to this object.
137
137
 
138
- linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
138
+ linkback = (options[:linkback].to_s || "#{MetaUtils.expand(self)}_oid").to_s
139
139
 
140
140
  meta :descendants, klass, linkback
141
141
  meta :props_and_relations, HasOne.new(name, klass, :linkback => linkback)
@@ -175,7 +175,7 @@ module MetaLanguage
175
175
  # linkback is the property of the child object that 'links back'
176
176
  # to this object.
177
177
 
178
- linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
178
+ linkback = (options[:linkback] || "#{MetaUtils.expand(self)}_oid").to_s
179
179
 
180
180
  # keep belongs to metadata, useful for
181
181
  # reflection/scaffolding.
@@ -231,7 +231,7 @@ module MetaLanguage
231
231
  def many_to_many(name, klass, options = {})
232
232
  list_o = name.to_s
233
233
  prop_o = N::Inflector.singularize(list_o)
234
- list_m = options[:linkback] || N::Inflector.plural_name(self)
234
+ list_m = (options[:linkback] || N::Inflector.plural_name(self)).to_s
235
235
  prop_m = N::Inflector.singularize(list_m)
236
236
 
237
237
  # Exit if the class is allready indirectly 'enchanted' from the
@@ -242,7 +242,7 @@ module MetaLanguage
242
242
  # Add some metadata to the class to allow for automatic join table
243
243
  # calculation.
244
244
 
245
- meta :sql_join, klass, options
245
+ meta :sql_join, name, klass, options
246
246
 
247
247
  # FIXME: should add metadata for cascading delete.
248
248
 
@@ -253,25 +253,25 @@ module MetaLanguage
253
253
 
254
254
  module_eval %{
255
255
  def #{list_o}(extrasql = nil)
256
- Og.db.select("SELECT d.* FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
256
+ Og.db.select("SELECT d.* FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
257
257
  end
258
258
 
259
259
  def #{list_o}_count(extrasql = nil)
260
- Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
260
+ Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} d, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
261
261
  end
262
262
 
263
263
  def add_#{prop_o}(obj = nil)
264
264
  yield(obj = #{klass}.new) unless obj
265
265
  obj.save! unless obj.oid
266
- Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
266
+ Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass, name)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
267
267
  end
268
268
 
269
269
  def delete_#{prop_o}(obj_or_oid)
270
- Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
270
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key2=\#\{obj_or_oid.to_i\}")
271
271
  end
272
272
 
273
273
  def clear_#{list_o}
274
- Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\@oid")
274
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key1=\#\@oid")
275
275
  end
276
276
  }
277
277
 
@@ -279,25 +279,25 @@ module MetaLanguage
279
279
 
280
280
  klass.module_eval %{
281
281
  def #{list_m}(extrasql = nil)
282
- Og.db.select("SELECT s.* FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
282
+ Og.db.select("SELECT s.* FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
283
283
  end
284
284
 
285
285
  def #{list_m}_count(extrasql = nil)
286
- Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
286
+ Og.db.select("SELECT COUNT(*) FROM #{Og::Adapter.table(self)} s, #{Og::Adapter.join_table(self, klass, name)} j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
287
287
  end
288
288
 
289
289
  def add_#{prop_m}(obj = nil)
290
290
  yield(obj = #{self}.new) unless obj
291
291
  obj.save! unless obj.oid
292
- Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
292
+ Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass, name)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
293
293
  end
294
294
 
295
295
  def delete_#{prop_m}(obj_or_oid)
296
- Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
296
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key1=\#\{obj_or_oid.to_i\}")
297
297
  end
298
298
 
299
299
  def clear_#{list_m}
300
- Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\@oid")
300
+ Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass, name)} WHERE key2=\#\@oid")
301
301
  end
302
302
  }
303
303
  end