og 0.10.0 → 0.11.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: psql.rb 259 2005-02-15 08:54:54Z gmosx $
3
+ # $Id: psql.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
 
5
5
  require 'postgres'
6
6
 
@@ -8,7 +8,7 @@ require 'og/adapter'
8
8
  require 'og/connection'
9
9
  require 'glue/attribute'
10
10
 
11
- class Og
11
+ module Og
12
12
 
13
13
  # The PostgreSQL adapter. This adapter communicates with
14
14
  # an PostgreSQL rdbms. For extra documentation see
@@ -30,24 +30,6 @@ class PsqlAdapter < Adapter
30
30
  return nil unless date
31
31
  return "#{date.year}-#{date.month}-#{date.mday}"
32
32
  end
33
-
34
- def write_prop(p)
35
- if p.klass.ancestors.include?(Integer)
36
- return "#\{@#{p.symbol} || 'NULL'\}"
37
- elsif p.klass.ancestors.include?(Float)
38
- return "#\{@#{p.symbol} || 'NULL'\}"
39
- elsif p.klass.ancestors.include?(String)
40
- return "'#\{#{self.class}.escape(@#{p.symbol})\}'"
41
- elsif p.klass.ancestors.include?(Time)
42
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
43
- elsif p.klass.ancestors.include?(Date)
44
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
45
- elsif p.klass.ancestors.include?(TrueClass)
46
- return "#\{@#{p.symbol} ? \"'t'\" : 'NULL' \}"
47
- else
48
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
49
- end
50
- end
51
33
 
52
34
  def read_prop(p, idx)
53
35
  if p.klass.ancestors.include?(Integer)
@@ -94,7 +76,7 @@ class PsqlAdapter < Adapter
94
76
  end
95
77
 
96
78
  def new_connection(db)
97
- return Og::PsqlConnection.new(db)
79
+ return PsqlConnection.new(db)
98
80
  end
99
81
 
100
82
  def calc_field_index(klass, db)
@@ -116,7 +98,7 @@ class PsqlAdapter < Adapter
116
98
 
117
99
  sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
118
100
 
119
- # Create table constrains
101
+ # Create table constrains.
120
102
 
121
103
  if klass.__meta and constrains = klass.__meta[:sql_constrain]
122
104
  sql << ", #{constrains.join(', ')}"
@@ -124,7 +106,7 @@ class PsqlAdapter < Adapter
124
106
 
125
107
  sql << ") WITHOUT OIDS;"
126
108
 
127
- # Create indices
109
+ # Create indices.
128
110
 
129
111
  if klass.__meta and indices = klass.__meta[:sql_index]
130
112
  for data in indices
@@ -226,6 +208,11 @@ class PsqlConnection < Connection
226
208
  end
227
209
  end
228
210
 
211
+ def close
212
+ @store.close
213
+ super
214
+ end
215
+
229
216
  def query(sql)
230
217
  Logger.debug sql if $DBG
231
218
  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 259 2005-02-15 08:54:54Z gmosx $
3
+ # $Id: sqlite.rb 263 2005-02-23 13:45:08Z gmosx $
4
4
 
5
5
  require 'sqlite3'
6
6
  require 'fileutils'
@@ -9,7 +9,7 @@ require 'og/adapter'
9
9
  require 'og/connection'
10
10
  require 'glue/attribute'
11
11
 
12
- class Og
12
+ module Og
13
13
 
14
14
  # The SQLite adapter. This adapter communicates with
15
15
  # an SQLite3 rdbms. For extra documentation see
@@ -79,7 +79,7 @@ class SqliteAdapter < Adapter
79
79
  end
80
80
 
81
81
  def new_connection(db)
82
- return Og::SqliteConnection.new(db)
82
+ return SqliteConnection.new(db)
83
83
  end
84
84
 
85
85
  def calc_field_index(klass, db)
@@ -1,12 +1,12 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: backend.rb 249 2005-02-04 14:03:00Z gmosx $
3
+ # $Id: backend.rb 263 2005-02-23 13:45:08Z gmosx $
4
4
 
5
5
  require 'yaml'
6
6
 
7
7
  require 'og/connection'
8
8
 
9
- class Og
9
+ module Og
10
10
 
11
11
  # Abstract backend. A backend communicates with the RDBMS.
12
12
  # This is the base class for the various backend implementations.
@@ -1,8 +1,8 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: connection.rb 254 2005-02-10 12:44:05Z gmosx $
3
+ # $Id: connection.rb 265 2005-02-24 08:46:54Z gmosx $
4
4
 
5
- class Og;
5
+ module Og;
6
6
 
7
7
  require 'glue/property'
8
8
  require 'glue/array'
@@ -12,7 +12,7 @@ require 'glue/time'
12
12
  # functionality. A backend specific implementation file (driver)
13
13
  # implements all methods.
14
14
  #
15
- # == Future
15
+ # === Future
16
16
  #
17
17
  # - support caching.
18
18
  # - support prepared statements.
@@ -41,7 +41,6 @@ class Connection
41
41
  # Close the connection to the database.
42
42
 
43
43
  def close
44
- @store.close
45
44
  Logger.debug "Closed DB connection." if $DBG
46
45
  end
47
46
 
@@ -283,11 +282,12 @@ class Connection
283
282
  end
284
283
 
285
284
  # TODO: implement this as stored procedure? naaah.
285
+ # TODO: also handle many_to_many relations.
286
286
 
287
287
  transaction do |tx|
288
288
  tx.exec "DELETE FROM #{klass::DBTABLE} WHERE oid=#{oid}"
289
- if cascade and klass.__meta.include?(:has)
290
- klass.__meta[:has].each do |dclass, linkback|
289
+ if cascade and klass.__meta.include?(:descendants)
290
+ klass.__meta[:descendants].each do |dclass, linkback|
291
291
  tx.exec "DELETE FROM #{dclass::DBTABLE} WHERE #{linkback}=#{oid}"
292
292
  end
293
293
  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 255 2005-02-10 12:45:32Z gmosx $
3
+ # $Id: database.rb 265 2005-02-24 08:46:54Z gmosx $
4
4
 
5
5
  require 'glue/logger'
6
6
  require 'glue/attribute'
@@ -13,7 +13,7 @@ require 'glue/pool'
13
13
  require 'og/enchant'
14
14
  require 'og/meta'
15
15
 
16
- class Og
16
+ module Og
17
17
 
18
18
  # Encapsulates an Og Database.
19
19
 
@@ -87,8 +87,8 @@ class Database
87
87
  end
88
88
  end
89
89
 
90
- Logger.info "Og auto manages the following classes:"
91
- Logger.info "#{classes_to_manage.inspect}"
90
+ Logger.debug "Og auto manages the following classes:"
91
+ Logger.debug "#{classes_to_manage.inspect}"
92
92
 
93
93
  manage_classes(*classes_to_manage)
94
94
  end
@@ -201,7 +201,7 @@ class Database
201
201
  }
202
202
 
203
203
  # Create the schema for this class if not available.
204
- @adapter.create_table(klass, self)
204
+ @adapter.create_table(klass, self) if Og.create_schema
205
205
 
206
206
  # Precompile some code that gets executed all the time.
207
207
  # Deletion code is not precompiled, because it is not used
@@ -1,8 +1,8 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: meta.rb 198 2004-12-22 11:26:59Z gmosx $
3
+ # $Id$
4
4
 
5
- class Og
5
+ module Og
6
6
 
7
7
  module Enchant
8
8
 
@@ -60,6 +60,10 @@ module Enchant
60
60
  Og.db.delete(obj_or_oid, #{klass})
61
61
  end
62
62
 
63
+ def self.properties_and_relations
64
+ @@__meta[:props_and_relations]
65
+ end
66
+
63
67
  def each(&block)
64
68
  all.each(&block)
65
69
  end
@@ -1,17 +1,29 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: meta.rb 254 2005-02-10 12:44:05Z gmosx $
3
+ # $Id: meta.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
  #--
5
5
  # TODO:
6
6
  # - precreate the meta sql statements as much as possible to
7
7
  # avoid string interpolations.
8
8
  #++
9
9
 
10
- require 'og/adapter'
11
10
  require 'glue/inflector'
11
+ require 'og/adapter'
12
+ require 'og/typemacros'
12
13
 
13
- class Og
14
+ module Og
14
15
 
16
+ class Relation < N::Property
17
+ alias foreign_class klass
18
+ end
19
+
20
+ class Has < Relation; end
21
+ class HasMany < Has; end
22
+ class HasOne < Has; end
23
+ class ManyToMany < Has; end
24
+ class BelongsTo < Relation; end
25
+ class RefersTo < Relation; end
26
+
15
27
  # Some useful meta-language utilities.
16
28
 
17
29
  module MetaUtils # :nodoc: all
@@ -31,6 +43,9 @@ module MetaUtils # :nodoc: all
31
43
  # in order to avoid forward declarations a symbol is given instead
32
44
  # of a class. Other times on class is given at all, and
33
45
  # the inflection mechanism is used to infer the class name.
46
+ #--
47
+ # This is not used yet.
48
+ #++
34
49
 
35
50
  def self.resolve_class(name, klass)
36
51
  klass ||= N::Inflector.camelize(name)
@@ -86,7 +101,7 @@ module MetaLanguage
86
101
  prop_eval << ", :sql => '#{options[:sql]}'" if options[:sql]
87
102
  prop_eval << ", :extra_sql => '#{options[:extra_sql]}'" if options[:extra_sql]
88
103
 
89
- meta :belongs_to, klass
104
+ meta :props_and_relations, BelongsTo.new(name, klass, :property => "#{name}_oid".intern)
90
105
 
91
106
  module_eval %{
92
107
  #{prop_eval}
@@ -122,7 +137,8 @@ module MetaLanguage
122
137
 
123
138
  linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
124
139
 
125
- meta :has, [klass, linkback]
140
+ meta :descendants, klass, linkback
141
+ meta :props_and_relations, HasOne.new(name, klass, :linkback => linkback)
126
142
 
127
143
  module_eval %{
128
144
  def #{name}(extrasql = nil)
@@ -141,12 +157,17 @@ module MetaLanguage
141
157
  # Example:
142
158
  #
143
159
  # class MyObject
144
- # has_many :children, AnotherObject
160
+ # has_many :articles, Article
145
161
  # end
146
162
  #
147
163
  # creates the code:
148
164
  #
149
- # def children; ... end
165
+ # obj.articles
166
+ # obj.add_article(article)
167
+ # obj.add_article do |a|
168
+ # a.title = 'Title'
169
+ # a.body = 'Body'
170
+ # end
150
171
 
151
172
  def has_many(name, klass, options = {})
152
173
  name_s = N::Inflector.singularize(name.to_s)
@@ -159,7 +180,8 @@ module MetaLanguage
159
180
  # keep belongs to metadata, useful for
160
181
  # reflection/scaffolding.
161
182
 
162
- meta :has, [klass, linkback]
183
+ meta :descendants, klass, linkback
184
+ meta :props_and_relations, HasMany.new(name, klass, :linkback => linkback)
163
185
 
164
186
  module_eval %{
165
187
  def #{name}(extrasql = nil)
@@ -170,7 +192,8 @@ module MetaLanguage
170
192
  Og.db.count("SELECT COUNT(*) FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
171
193
  end
172
194
 
173
- def add_#{name_s}(obj, extra = nil)
195
+ def add_#{name_s}(obj = nil)
196
+ yield(obj = #{klass}.new) unless obj
174
197
  obj.#{linkback} = @oid
175
198
  obj.save!
176
199
  end
@@ -196,6 +219,7 @@ module MetaLanguage
196
219
  # article.categories
197
220
  # article.del_category
198
221
  # article.add_category
222
+ # article.add_category { |c| ... }
199
223
  # article.clear_categories
200
224
  #
201
225
  # category.articles
@@ -210,7 +234,7 @@ module MetaLanguage
210
234
  list_m = options[:linkback] || N::Inflector.plural_name(self)
211
235
  prop_m = N::Inflector.singularize(list_m)
212
236
 
213
- # exit if the class is allready indirectly 'enchanted' from the
237
+ # Exit if the class is allready indirectly 'enchanted' from the
214
238
  # other class of the many_to_many relation.
215
239
 
216
240
  return if self.respond_to?(prop_m)
@@ -218,27 +242,31 @@ module MetaLanguage
218
242
  # Add some metadata to the class to allow for automatic join table
219
243
  # calculation.
220
244
 
221
- meta :sql_join, [klass, options]
245
+ meta :sql_join, klass, options
246
+
247
+ # FIXME: should add metadata for cascading delete.
222
248
 
223
- meta :many_to_many, klass
224
- klass.meta :many_to_many, self
249
+ meta :props_and_relations, ManyToMany.new(prop_o, klass)
250
+ klass.meta :props_and_relations, ManyToMany.new(prop_m, self)
225
251
 
226
- # enchant this class
252
+ # Enchant this class
227
253
 
228
254
  module_eval %{
229
255
  def #{list_o}(extrasql = nil)
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})
231
- end
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})
257
+ end
232
258
 
233
259
  def #{list_o}_count(extrasql = nil)
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})
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})
235
261
  end
236
262
 
237
- def add_#{prop_o}(obj, extra = nil)
263
+ def add_#{prop_o}(obj = nil)
264
+ yield(obj = #{klass}.new) unless obj
265
+ obj.save! unless obj.oid
238
266
  Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
239
267
  end
240
268
 
241
- def delete_#{prop_o}(obj_or_oid, extra = nil)
269
+ def delete_#{prop_o}(obj_or_oid)
242
270
  Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
243
271
  end
244
272
 
@@ -251,18 +279,20 @@ module MetaLanguage
251
279
 
252
280
  klass.module_eval %{
253
281
  def #{list_m}(extrasql = nil)
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})
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})
255
283
  end
256
284
 
257
285
  def #{list_m}_count(extrasql = nil)
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})
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})
259
287
  end
260
288
 
261
- def add_#{prop_m}(obj, extra = nil)
289
+ def add_#{prop_m}(obj = nil)
290
+ yield(obj = #{self}.new) unless obj
291
+ obj.save! unless obj.oid
262
292
  Og.db.exec("INSERT INTO #{Og::Adapter.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
263
293
  end
264
294
 
265
- def delete_#{prop_m}(obj_or_oid, extra = nil)
295
+ def delete_#{prop_m}(obj_or_oid)
266
296
  Og.db.exec("DELETE FROM #{Og::Adapter.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
267
297
  end
268
298
 
@@ -300,8 +330,8 @@ module MetaLanguage
300
330
  prop_eval << ", :sql => '#{options[:sql]}'" if options[:sql]
301
331
  prop_eval << ", :extra_sql => '#{options[:extra_sql]}'" if options[:extra_sql]
302
332
 
303
- meta :refers_to, klass
304
- klass.meta :has, [self, "#{name}_oid"]
333
+ meta :props_and_relations, RefersTo.new(name, klass, :property => "#{name}_oid".intern)
334
+ klass.meta :descendants, self, "#{name}_oid".intern
305
335
 
306
336
  module_eval %{
307
337
  #{prop_eval}
@@ -321,7 +351,7 @@ module MetaLanguage
321
351
  # methods are generated.
322
352
 
323
353
  def joins(klass, options = {})
324
- meta :joins, [klass, options]
354
+ meta :joins, klass, options
325
355
  end
326
356
 
327
357
  end
@@ -7,7 +7,7 @@ require 'flexmock'
7
7
 
8
8
  require 'og'
9
9
 
10
- class Og
10
+ module Og
11
11
 
12
12
  # A utility object to Mock a Database in test units.
13
13
  # Extends the standard FlexMock object.
@@ -0,0 +1,23 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: typemacros.rb 267 2005-02-28 14:52:41Z gmosx $
4
+
5
+ module Og
6
+
7
+ # Some useful type macros to help when defining managed
8
+ # objects. You can easily code your own type macros.
9
+ # Just return the array that should be passed
10
+ #
11
+ # === Example
12
+ #
13
+ # property :name, Og.VarChar(30)
14
+
15
+ def VarChar(size)
16
+ return String, :sql => "VARCHAR(#{size})"
17
+ end
18
+
19
+ NotNull = {:sql => "NOT NULL"}.freeze
20
+
21
+ Null = {:sql => "NULL"}.freeze
22
+
23
+ end