og 0.13.0 → 0.14.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: connection.rb 281 2005-03-10 12:24:14Z gmosx $
3
+ # $Id: connection.rb 326 2005-03-28 11:07:17Z gmosx $
4
4
 
5
5
  module Og;
6
6
 
@@ -12,10 +12,10 @@ require 'glue/time'
12
12
  # functionality. A backend specific implementation file (driver)
13
13
  # implements all methods.
14
14
  #
15
- # === Future
16
- #
15
+ #--
17
16
  # - support caching.
18
17
  # - support prepared statements.
18
+ #++
19
19
 
20
20
  class Connection
21
21
 
@@ -139,6 +139,12 @@ class Connection
139
139
  raise 'Not implemented!'
140
140
  end
141
141
 
142
+ # Get a row from the resultset.
143
+
144
+ def get_row(res)
145
+ return res
146
+ end
147
+
142
148
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143
149
  # :section: Managed object methods.
144
150
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -187,6 +193,7 @@ class Connection
187
193
  exec "UPDATE #{klass::DBTABLE} SET #{update_sql} WHERE oid=#{oid}"
188
194
  end
189
195
  alias_method :pupdate, :update_properties
196
+ alias_method :update_propery, :update_properties
190
197
 
191
198
  # Load an object from the database.
192
199
  #
@@ -282,7 +289,7 @@ class Connection
282
289
  # this is a class callback!
283
290
 
284
291
  if klass.respond_to?(:og_pre_delete)
285
- klass.og_pre_delete(self, oid)
292
+ klass.og_pre_delete(self, obj_or_oid)
286
293
  end
287
294
 
288
295
  # TODO: implement this as stored procedure? naaah.
@@ -298,7 +305,21 @@ class Connection
298
305
  end
299
306
  end
300
307
  alias_method :delete!, :delete
301
-
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
+
302
323
  end
303
324
 
304
325
  end
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: database.rb 281 2005-03-10 12:24:14Z gmosx $
3
+ # $Id: database.rb 326 2005-03-28 11:07:17Z gmosx $
4
4
 
5
5
  require 'glue/logger'
6
6
  require 'glue/attribute'
@@ -65,6 +65,8 @@ class Database
65
65
 
66
66
  @adapter = Adapter.for_name(@config[:adapter])
67
67
 
68
+ self.class.drop!(config) if config[:drop]
69
+
68
70
  @connection_pool = N::Pool.new
69
71
  @managed_classes = N::SafeHash.new
70
72
 
@@ -72,26 +74,7 @@ class Database
72
74
  @connection_pool << @adapter.new_connection(self)
73
75
  end
74
76
 
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.debug "Og auto manages the following classes:"
91
- Logger.debug "#{classes_to_manage.inspect}"
92
-
93
- manage_classes(*classes_to_manage)
94
- end
77
+ auto_manage_classes if Og.auto_manage_classes
95
78
 
96
79
  # use the newly created database.
97
80
  Og.use(self)
@@ -169,6 +152,32 @@ class Database
169
152
  manage(klass)
170
153
  end
171
154
  end
155
+
156
+ # Use Ruby's advanced reflection features to find
157
+ # and manage all manageable classes. Manageable are all
158
+ # classes that include Properties or Metadata.
159
+ #--
160
+ # gmosx, FIXME: this automanage code is not elegant and slow
161
+ # should probably recode this, along with glue/property.rb
162
+ # FIXME: can this be optimized?
163
+ # TODO: find a better name.
164
+ #++
165
+
166
+ def auto_manage_classes
167
+ classes_to_manage = []
168
+
169
+ ObjectSpace.each_object(Class) do |c|
170
+ if c.respond_to?(:__props) and c.__props
171
+ classes_to_manage << c
172
+ end
173
+ end
174
+
175
+ Logger.debug "Og auto manages the following classes:"
176
+ Logger.debug "#{classes_to_manage.inspect}"
177
+
178
+ manage_classes(*classes_to_manage)
179
+ end
180
+ alias_method :auto_manage, :auto_manage_classes
172
181
 
173
182
  # Stop managing a Ruby class
174
183
 
@@ -177,7 +186,7 @@ class Database
177
186
  end
178
187
 
179
188
  # Is this class managed?
180
- #
189
+
181
190
  def managed?(klass)
182
191
  return @managed_classes.include?(klass)
183
192
  end
@@ -212,11 +221,6 @@ class Database
212
221
  # Create the schema for this class if not available.
213
222
 
214
223
  @adapter.create_table(klass, self) if Og.create_schema
215
-
216
- # @adapter.eval_og_insert(klass, self)
217
- # @adapter.eval_og_update(klass, self)
218
- # @adapter.eval_og_read(klass, self)
219
-
220
224
  @adapter.eval_lifecycle_methods(klass, self)
221
225
  end
222
226
 
@@ -257,6 +261,8 @@ class Database
257
261
  wrap_method :prepare, 'sql'
258
262
  wrap_method :query, 'sql'
259
263
  wrap_method :exec, 'sql'
264
+ wrap_method :get_row, 'res'
265
+ wrap_method :transaction, '&block'
260
266
 
261
267
  class << self
262
268
 
@@ -43,6 +43,14 @@ module Enchant
43
43
  @@og_db.load_all(#{klass}, extra_sql)
44
44
  end
45
45
 
46
+ def self.update_all(set_sql, extra_sql = nil)
47
+ @@og_db.exec("UPDATE #{klass::DBTABLE} SET \#\{set_sql\} \#\{extra_sql\}")
48
+ end
49
+
50
+ def self.update(set_sql, extra_sql = nil)
51
+ @@og_db.exec("UPDATE #{klass::DBTABLE} SET \#\{set_sql\} \#\{extra_sql\}")
52
+ end
53
+
46
54
  def self.count(sql = "SELECT COUNT(*) FROM #{klass::DBTABLE}")
47
55
  @@og_db.count(sql, #{klass})
48
56
  end
@@ -71,11 +79,15 @@ module Enchant
71
79
  @@og_db.delete(obj_or_oid, #{klass})
72
80
  end
73
81
 
82
+ def self.transaction(&block)
83
+ @@og_db.transaction(&block)
84
+ end
85
+
74
86
  def self.properties_and_relations
75
87
  @@__meta[:props_and_relations]
76
88
  end
77
89
 
78
- def each(&block)
90
+ def self.each(&block)
79
91
  all.each(&block)
80
92
  end
81
93
  include Enumerable
@@ -85,14 +97,26 @@ module Enchant
85
97
  return self
86
98
  end
87
99
  alias_method :save!, :save
88
-
100
+
101
+ def reload
102
+ raise 'Cannot reload unmanaged object' unless @oid
103
+ res = @@og_db.query "SELECT * FROM #{klass::DBTABLE} WHERE oid=\#\{@oid\}"
104
+ og_read(@@og_db.get_row(res))
105
+ end
106
+ alias_method :reload!, :reload
107
+
89
108
  def update_properties(updatesql)
90
109
  @@og_db.pupdate(updatesql, self.oid, #{klass})
91
110
  end
92
- alias_method :pupdate!, :update_properties
111
+ alias_method :pupdate, :update_properties
112
+ alias_method :update_property, :update_properties
113
+
114
+ def set_property(prop, value)
115
+ @@og_db.pupdate("\#\{prop\}=\#\{value\}", self.oid, #{klass})
116
+ end
93
117
 
94
118
  def delete!
95
- @@og_db.delete(@oid, #{klass})
119
+ @@og_db.delete(self, #{klass})
96
120
  end
97
121
  }
98
122
 
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: meta.rb 281 2005-03-10 12:24:14Z gmosx $
3
+ # $Id: meta.rb 326 2005-03-28 11:07:17Z gmosx $
4
4
  #--
5
5
  # TODO:
6
6
  # - precreate the meta sql statements as much as possible to
@@ -11,6 +11,8 @@ require 'glue/inflector'
11
11
  require 'og/adapter'
12
12
  require 'og/typemacros'
13
13
 
14
+ require 'og/mixins/list'
15
+
14
16
  module Og
15
17
 
16
18
  class Relation < N::Property
@@ -138,7 +140,7 @@ module MetaLanguage
138
140
  linkback = (options[:linkback].to_s || "#{MetaUtils.expand(self)}_oid").to_s
139
141
 
140
142
  meta :descendants, klass, linkback
141
- meta :props_and_relations, HasOne.new(name, klass, :linkback => linkback)
143
+ meta :props_and_relations, HasOne.new(name, klass, options)
142
144
 
143
145
  module_eval %{
144
146
  def #{name}(extrasql = nil)
@@ -150,10 +152,18 @@ module MetaLanguage
150
152
  end
151
153
  }
152
154
  end
153
-
155
+
154
156
  # Implements a 'has_many' relation.
155
157
  # Automatically enchants the calling class with helper methods.
156
158
  #
159
+ # Options:
160
+ #
161
+ # [+linkback+]
162
+ #
163
+ # [+order+]
164
+ #
165
+ # [+extrasql+]
166
+ #
157
167
  # Example:
158
168
  #
159
169
  # class MyObject
@@ -176,16 +186,21 @@ module MetaLanguage
176
186
  # to this object.
177
187
 
178
188
  linkback = (options[:linkback] || "#{MetaUtils.expand(self)}_oid").to_s
189
+
190
+ if order = options[:order]
191
+ order = "ORDER BY #{order}"
192
+ end
193
+ default_extrasql = "#{order}#{options[:sql]}"
179
194
 
180
195
  # keep belongs to metadata, useful for
181
196
  # reflection/scaffolding.
182
197
 
183
198
  meta :descendants, klass, linkback
184
- meta :props_and_relations, HasMany.new(name, klass, :linkback => linkback)
199
+ meta :props_and_relations, HasMany.new(name, klass, options)
185
200
 
186
201
  code = %{
187
202
  def #{name}(extrasql = nil)
188
- Og.db.select("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}", #{klass})
203
+ Og.db.select("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid #{default_extrasql} \#\{extrasql\}", #{klass})
189
204
  end
190
205
 
191
206
  def #{name}_count(extrasql = nil)
@@ -380,5 +395,15 @@ end
380
395
  if Og.include_meta_language
381
396
  class Module # :nodoc: all
382
397
  include Og::MetaLanguage
398
+ include Og::List
399
+ =begin
400
+ A hack to avoid forward references. Does not work
401
+ with namespave modules though. Any idea?
402
+ -> try TOPLEVEL_BINDING
403
+
404
+ def const_missing(sym)
405
+ eval "class ::#{sym}; end; return #{sym}"
406
+ end
407
+ =end
383
408
  end
384
409
  end
@@ -0,0 +1,158 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: list.rb 326 2005-03-28 11:07:17Z gmosx $
4
+
5
+ module Og
6
+
7
+ # Attach list/ordering methods to the enchanted class.
8
+ #--
9
+ # TODO:
10
+ # Convert to new Og filter system.
11
+ # Implement as super-mixin.
12
+ #++
13
+
14
+ module List
15
+
16
+ # The enchanted object acts as a list item.
17
+
18
+ def acts_as_list(options = {})
19
+ c = { :position => 'position', :type => Fixnum, :scope => '1 = 1' }
20
+ c.update(options) if options.is_a?(Hash)
21
+ c[:scope] = "#{c[:scope]}_oid".intern if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
22
+
23
+ position = c[:position]
24
+ scope = c[:scope]
25
+
26
+ if scope.is_a?(Symbol)
27
+ scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
28
+ end
29
+
30
+ module_eval <<-EOE, __FILE__, __LINE__
31
+ property :#{position}, #{c[:type]}
32
+
33
+ def og_pre_insert(conn)
34
+ add_to_bottom
35
+ end
36
+
37
+ def self.og_pre_delete(conn, obj)
38
+ obj.decrement_position_of_lower_items
39
+ end
40
+
41
+ def move_higher
42
+ if higher = higher_item
43
+ #{self}.transaction do
44
+ higher.increment_position
45
+ decrement_position
46
+ end
47
+ end
48
+ end
49
+
50
+ def move_lower
51
+ if lower = lower_item
52
+ #{self}.transaction do
53
+ lower.decrement_position
54
+ increment_position
55
+ end
56
+ end
57
+ end
58
+
59
+ def move_to_top
60
+ #{self}.transaction do
61
+ increment_position_of_higher_items
62
+ set_top_position
63
+ end
64
+ end
65
+
66
+ def move_to_bottom
67
+ #{self}.transaction do
68
+ decrement_position_of_lower_items
69
+ set_bottom_position
70
+ end
71
+ end
72
+
73
+ def move_to
74
+ end
75
+
76
+ def add_to_top
77
+ increment_position_of_all_items
78
+ end
79
+
80
+ def add_to_bottom
81
+ @#{position} = bottom_position + 1
82
+ end
83
+
84
+ def add_to
85
+ end
86
+
87
+ def higher_item
88
+ #{self}.one(#{scope} + " AND #{position}=\#\{@#{position} - 1\}")
89
+ end
90
+ alias_method :previous_item, :higher_item
91
+
92
+ def lower_item
93
+ #{self}.one(#{scope} + " AND #{position}=\#\{@#{position} + 1\}")
94
+ end
95
+ alias_method :next_item, :lower_item
96
+
97
+ def top_item
98
+ end
99
+ alias_method :first_item, :top_item
100
+
101
+ def bottom_item
102
+ #{self}.one(#{scope} + " ORDER BY #{position} DESC")
103
+ end
104
+ alias_method :last_item, :last_item
105
+
106
+ def top?
107
+ @#{position} == 1
108
+ end
109
+ alias_method :first?, :top?
110
+
111
+ def bottom?
112
+ @#{position} == bottom_position
113
+ end
114
+ alias_method :last?, :bottom?
115
+
116
+ def increment_position
117
+ @#{position} += 1
118
+ set_property('#{position}', @#{position})
119
+ end
120
+
121
+ def decrement_position
122
+ @#{position} -= 1
123
+ set_property('#{position}', @#{position})
124
+ end
125
+
126
+ def bottom_position
127
+ item = bottom_item
128
+ item ? item.#{position} : 0
129
+ end
130
+
131
+ def set_top_position
132
+ @#{position} = 1
133
+ set_property('#{position}', 1)
134
+ end
135
+
136
+ def set_bottom_position
137
+ @#{position} = bottom_position + 1
138
+ set_property('#{position}', @#{position})
139
+ end
140
+
141
+ def increment_position_of_higher_items
142
+ #{self}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope} + " AND #{position} < \#\{@#{position}\}")
143
+ end
144
+
145
+ def increment_position_of_all_items
146
+ #{self}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope})
147
+ end
148
+
149
+ def decrement_position_of_lower_items
150
+ #{self}.update("#{position}=(#{position} - 1)", "WHERE " + #{scope} + " AND #{position} > \#\{@#{position}\}")
151
+ end
152
+ EOE
153
+ end
154
+
155
+
156
+ end
157
+
158
+ end