og 0.13.0 → 0.14.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.
@@ -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