og 0.10.0 → 0.11.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: 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