og 0.6.0 → 0.7.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.
- data/ChangeLog +183 -0
- data/ChangeLog.1 +2344 -0
- data/README.og +4 -3
- data/RELEASES.og +15 -0
- data/Rakefile +135 -0
- data/examples/og/README +7 -0
- data/examples/og/mock_example.rb +58 -0
- data/examples/og/run.rb +9 -5
- data/lib/glue/property.rb +166 -107
- data/lib/glue/property.rb.old +307 -0
- data/lib/og.rb +17 -6
- data/lib/og/backend.rb +34 -4
- data/lib/og/backends/mysql.rb +3 -17
- data/lib/og/backends/psql.rb +5 -17
- data/lib/og/meta.rb +41 -26
- data/lib/og/mock.rb +223 -0
- data/lib/og/version.rb +2 -2
- data/test/og/tc_lifecycle.rb +107 -0
- data/test/tc_og.rb +31 -4
- metadata +22 -14
data/lib/og/backends/psql.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: psql.rb
|
5
|
+
# $Id: psql.rb 194 2004-12-20 20:23:57Z gmosx $
|
6
6
|
|
7
7
|
require "postgres"
|
8
8
|
|
@@ -137,6 +137,8 @@ end
|
|
137
137
|
# = PsqlBackend
|
138
138
|
#
|
139
139
|
# Implements a PostgreSQL powered backend.
|
140
|
+
# This backend is compatible with Michael Neumann's postgres-pr
|
141
|
+
# pure ruby driver.
|
140
142
|
#
|
141
143
|
class PsqlBackend < Og::Backend
|
142
144
|
|
@@ -240,21 +242,7 @@ class PsqlBackend < Og::Backend
|
|
240
242
|
# and constrains are created (indicices, sequences, etc).
|
241
243
|
#
|
242
244
|
def create_table(klass)
|
243
|
-
fields =
|
244
|
-
|
245
|
-
klass.__props.each do |p|
|
246
|
-
klass.sql_index(p.symbol) if p.meta[:sql_index]
|
247
|
-
|
248
|
-
field = "#{p.symbol}"
|
249
|
-
|
250
|
-
if p.meta and p.meta[:sql]
|
251
|
-
field << " #{p.meta[:sql]}"
|
252
|
-
else
|
253
|
-
field << " #{TYPEMAP[p.klass]}"
|
254
|
-
end
|
255
|
-
|
256
|
-
fields << field
|
257
|
-
end
|
245
|
+
fields = create_fields(klass, TYPEMAP)
|
258
246
|
|
259
247
|
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
260
248
|
|
@@ -319,7 +307,7 @@ class PsqlBackend < Og::Backend
|
|
319
307
|
join_src = "#{Og::Utils.encode(klass)}_oid"
|
320
308
|
join_dst = "#{Og::Utils.encode(join_class)}_oid"
|
321
309
|
begin
|
322
|
-
exec "CREATE TABLE #{join_table} ( key1 integer, key2 integer )"
|
310
|
+
exec "CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )"
|
323
311
|
exec "CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)"
|
324
312
|
exec "CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)"
|
325
313
|
rescue => ex
|
data/lib/og/meta.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: meta.rb
|
5
|
+
# $Id: meta.rb 198 2004-12-22 11:26:59Z gmosx $
|
6
6
|
|
7
7
|
require 'og/backend'
|
8
8
|
require 'glue/inflector'
|
@@ -17,7 +17,9 @@ module MetaUtils # :nodoc: all
|
|
17
17
|
|
18
18
|
# Conver the klass to a string representation
|
19
19
|
# The leading module if available is removed.
|
20
|
-
|
20
|
+
#--
|
21
|
+
# gmosx, FIXME: unify with the ogutils.encode method?
|
22
|
+
#++
|
21
23
|
def self.expand(klass)
|
22
24
|
return klass.name.gsub(/^.*::/, '').gsub(/::/, '_').downcase
|
23
25
|
end
|
@@ -46,7 +48,7 @@ module MetaLanguage
|
|
46
48
|
# Example:
|
47
49
|
#
|
48
50
|
# class MyObject
|
49
|
-
# belongs_to AnotherObject, :parent
|
51
|
+
# belongs_to AnotherObject, :prop => :parent
|
50
52
|
# end
|
51
53
|
#
|
52
54
|
# creates the code:
|
@@ -56,8 +58,12 @@ module MetaLanguage
|
|
56
58
|
# def parent=(obj_or_oid); ... end
|
57
59
|
#
|
58
60
|
def belongs_to(name, klass, options = {})
|
61
|
+
prop_eval = "prop_accessor Fixnum, :#{name}_oid"
|
62
|
+
prop_eval << ", :sql => '#{options[:sql]}'" if options[:sql]
|
63
|
+
prop_eval << ", :extra_sql => '#{options[:extra_sql]}'" if options[:extra_sql]
|
64
|
+
|
59
65
|
module_eval %{
|
60
|
-
|
66
|
+
#{prop_eval}
|
61
67
|
|
62
68
|
def #{name}
|
63
69
|
$og.load_by_oid(@#{name}_oid, #{klass})
|
@@ -75,14 +81,14 @@ module MetaLanguage
|
|
75
81
|
# Example:
|
76
82
|
#
|
77
83
|
# class MyObject
|
78
|
-
# has_one
|
84
|
+
# has_one AnotherObject
|
79
85
|
# end
|
80
86
|
#
|
81
87
|
# creates the code:
|
82
88
|
#
|
83
|
-
#
|
89
|
+
# ...
|
84
90
|
#
|
85
|
-
def has_one(
|
91
|
+
def has_one(name, klass, options = {})
|
86
92
|
# linkback is the property of the child object that 'links back'
|
87
93
|
# to this object.
|
88
94
|
linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
|
@@ -117,6 +123,8 @@ module MetaLanguage
|
|
117
123
|
# def children; ... end
|
118
124
|
#
|
119
125
|
def has_many(name, klass, options = {})
|
126
|
+
name_s = G::Inflector.singularize(name.to_s)
|
127
|
+
|
120
128
|
# linkback is the property of the child object that 'links back'
|
121
129
|
# to this object.
|
122
130
|
linkback = options[:linkback] || "#{MetaUtils.expand(self)}_oid"
|
@@ -138,6 +146,11 @@ module MetaLanguage
|
|
138
146
|
def #{name}_count(extrasql = nil)
|
139
147
|
$og.count("SELECT COUNT(*) FROM #{Utils.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\}")
|
140
148
|
end
|
149
|
+
|
150
|
+
def add_#{name_s}(obj, extra = nil)
|
151
|
+
obj.#{linkback} = @oid
|
152
|
+
obj.save!
|
153
|
+
end
|
141
154
|
}
|
142
155
|
end
|
143
156
|
|
@@ -145,10 +158,12 @@ module MetaLanguage
|
|
145
158
|
# Two objects are associated using an intermediate join table.
|
146
159
|
# Automatically enchants the calling class with helper methods.
|
147
160
|
#
|
161
|
+
# Options:
|
162
|
+
#
|
148
163
|
# Example:
|
149
164
|
#
|
150
165
|
# class Article
|
151
|
-
#
|
166
|
+
# many_to_many :categories, Category, :linkback => articles
|
152
167
|
# end
|
153
168
|
#
|
154
169
|
# article.categories
|
@@ -162,15 +177,15 @@ module MetaLanguage
|
|
162
177
|
#--
|
163
178
|
# FIXME: make more compatible with other enchant methods.
|
164
179
|
#++
|
165
|
-
def many_to_many(klass, options = {})
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
180
|
+
def many_to_many(name, klass, options = {})
|
181
|
+
list_o = name.to_s
|
182
|
+
prop_o = G::Inflector.singularize(list_o)
|
183
|
+
list_m = options[:linkback] || G::Inflector.plural_name(self)
|
184
|
+
prop_m = G::Inflector.singularize(list_m)
|
170
185
|
|
171
186
|
# exit if the class is allready indirectly 'enchanted' from the
|
172
187
|
# other class of the many_to_many relation.
|
173
|
-
return if self.respond_to?(
|
188
|
+
return if self.respond_to?(prop_m)
|
174
189
|
|
175
190
|
# Add some metadata to the class to allow for automatic join table
|
176
191
|
# calculation.
|
@@ -181,24 +196,24 @@ module MetaLanguage
|
|
181
196
|
# enchant this class
|
182
197
|
|
183
198
|
module_eval %{
|
184
|
-
def #{
|
199
|
+
def #{list_o}(extrasql = nil)
|
185
200
|
$og.select("SELECT d.* FROM #{Utils.table(klass)} AS d, #{Utils.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
|
186
201
|
end
|
187
202
|
|
188
|
-
def #{
|
203
|
+
def #{list_o}_count(extrasql = nil)
|
189
204
|
$og.select("SELECT COUNT(*) FROM #{Utils.table(klass)} AS d, #{Utils.join_table(self, klass)} AS j WHERE j.key1=\#\@oid AND j.key2=d.oid \#\{extrasql\}", #{klass})
|
190
205
|
end
|
191
206
|
|
192
|
-
def add_#{
|
207
|
+
def add_#{prop_o}(obj, extra = nil)
|
193
208
|
$og.exec("INSERT INTO #{Utils.join_table(self, klass)} (key1, key2) VALUES (\#\@oid, \#\{obj.oid\})")
|
194
209
|
end
|
195
210
|
|
196
|
-
def del_#{
|
211
|
+
def del_#{prop_o}(obj_or_oid, extra = nil)
|
197
212
|
$og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key2=\#\{obj_or_oid.to_i\}")
|
198
213
|
end
|
199
|
-
alias_method :delete_#{
|
214
|
+
alias_method :delete_#{prop_o}, :del_#{prop_o}
|
200
215
|
|
201
|
-
def clear_#{
|
216
|
+
def clear_#{list_o}
|
202
217
|
$og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key1=\#\@oid")
|
203
218
|
end
|
204
219
|
}
|
@@ -206,24 +221,24 @@ module MetaLanguage
|
|
206
221
|
# indirectly enchant the other class of the relation.
|
207
222
|
|
208
223
|
klass.module_eval %{
|
209
|
-
def #{
|
224
|
+
def #{list_m}(extrasql = nil)
|
210
225
|
$og.select("SELECT s.* FROM #{Utils.table(self)} AS s, #{Utils.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
|
211
226
|
end
|
212
227
|
|
213
|
-
def #{
|
228
|
+
def #{list_m}_count(extrasql = nil)
|
214
229
|
$og.select("SELECT COUNT(*) FROM #{Utils.table(self)} AS s, #{Utils.join_table(self, klass)} AS j WHERE j.key2=\#\@oid AND j.key1=s.oid \#\{extrasql\}", #{self})
|
215
230
|
end
|
216
231
|
|
217
|
-
def add_#{
|
232
|
+
def add_#{prop_m}(obj, extra = nil)
|
218
233
|
$og.exec("INSERT INTO #{Utils.join_table(self, klass)} (key1, key2) VALUES (\#\{obj.oid\}, \#\@oid)")
|
219
234
|
end
|
220
235
|
|
221
|
-
def del_#{
|
236
|
+
def del_#{prop_m}(obj_or_oid, extra = nil)
|
222
237
|
$og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key1=\#\{obj_or_oid.to_i\}")
|
223
238
|
end
|
224
|
-
alias_method :delete_#{
|
239
|
+
alias_method :delete_#{prop_m}, :del_#{prop_m}
|
225
240
|
|
226
|
-
def clear_#{
|
241
|
+
def clear_#{list_m}
|
227
242
|
$og.exec("DELETE FROM #{Utils.join_table(self, klass)} WHERE key2=\#\@oid")
|
228
243
|
end
|
229
244
|
}
|
data/lib/og/mock.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
# code:
|
2
|
+
# * George Moschovitis <gm@navel.gr>
|
3
|
+
# * Thomas Quas <tquas@yahoo.com>
|
4
|
+
#
|
5
|
+
# (c) 2004 Navel, all rights reserved.
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
require 'og'
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require_gem 'flexmock'
|
12
|
+
|
13
|
+
module Og
|
14
|
+
|
15
|
+
# = MockDatabase
|
16
|
+
#
|
17
|
+
# A utility object to Mock a Database in test units.
|
18
|
+
# Extends the standard FlexMock object.
|
19
|
+
#
|
20
|
+
#--
|
21
|
+
# TODO: Factor out common functionality with Database
|
22
|
+
# to avoid code duplication.
|
23
|
+
#++
|
24
|
+
class MockDatabase < ::FlexMock
|
25
|
+
|
26
|
+
# Managed class metadata
|
27
|
+
#
|
28
|
+
class ManagedClassMeta
|
29
|
+
# The managed class.
|
30
|
+
attr_accessor :klass
|
31
|
+
|
32
|
+
# A mapping of the database fields to the object properties.
|
33
|
+
attr_accessor :field_index
|
34
|
+
|
35
|
+
def initialize(klass = nil)
|
36
|
+
@klass = klass
|
37
|
+
@field_index = {}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# hash of configuration options.
|
42
|
+
attr_accessor :config
|
43
|
+
|
44
|
+
# Pool of connections to the backend.
|
45
|
+
attr_accessor :connection_pool
|
46
|
+
|
47
|
+
# Managed classes.
|
48
|
+
attr_accessor :managed_classes
|
49
|
+
|
50
|
+
# Initialize the database interface.
|
51
|
+
#
|
52
|
+
def initialize
|
53
|
+
# Initialize FlexMock
|
54
|
+
super
|
55
|
+
|
56
|
+
@managed_classes = G::SafeHash.new
|
57
|
+
|
58
|
+
$log.info "Using mock database."
|
59
|
+
|
60
|
+
if $og_auto_manage_classes
|
61
|
+
# automatically manage classes with properties and metadata.
|
62
|
+
# gmosx: Any idea how to optimize this?
|
63
|
+
classes_to_manage = []
|
64
|
+
ObjectSpace.each_object(Class) do |c|
|
65
|
+
if c.respond_to?(:__props) and c.__props
|
66
|
+
classes_to_manage << c
|
67
|
+
end
|
68
|
+
end
|
69
|
+
$log.info "Og auto manages the following classes:"
|
70
|
+
$log.info "#{classes_to_manage.inspect}"
|
71
|
+
manage_classes(*classes_to_manage)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Shutdown the database interface.
|
76
|
+
#
|
77
|
+
def shutdown
|
78
|
+
end
|
79
|
+
alias_method :close, :shutdown
|
80
|
+
|
81
|
+
# Register a standard Ruby class as managed.
|
82
|
+
#
|
83
|
+
def manage(klass)
|
84
|
+
return if managed?(klass) or klass.ancestors.include?(Og::Unmanageable)
|
85
|
+
|
86
|
+
@managed_classes[klass] = ManagedClassMeta.new(klass)
|
87
|
+
|
88
|
+
# Add standard og methods to the class.
|
89
|
+
convert(klass)
|
90
|
+
|
91
|
+
# Add helper methods to the class.
|
92
|
+
enchant(klass) if $og_enchant_managed_classes
|
93
|
+
end
|
94
|
+
|
95
|
+
# Helper method to set multiple managed classes.
|
96
|
+
#
|
97
|
+
def manage_classes(*klasses)
|
98
|
+
for klass in klasses
|
99
|
+
manage(klass)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Stop managing a Ruby class
|
104
|
+
#
|
105
|
+
def unmanage(klass)
|
106
|
+
@managed_classes.delete(klass)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Is this class managed?
|
110
|
+
#
|
111
|
+
def managed?(klass)
|
112
|
+
return @managed_classes.include?(klass)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Add standard og functionality to the class
|
116
|
+
#
|
117
|
+
def convert(klass)
|
118
|
+
klass.class_eval %{
|
119
|
+
DBTABLE = "#{Og::Utils.table(klass)}"
|
120
|
+
DBSEQ = "#{Og::Utils.table(klass)}_oids_seq"
|
121
|
+
|
122
|
+
def to_i()
|
123
|
+
@oid
|
124
|
+
end
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
# Enchant a managed class. Add useful DB related methods to the
|
129
|
+
# class and its instances.
|
130
|
+
#
|
131
|
+
def enchant(klass)
|
132
|
+
klass.class_eval %{
|
133
|
+
def self.save(obj)
|
134
|
+
$og << obj
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.load(oid_or_name)
|
138
|
+
$og.load(oid_or_name, #{klass})
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.[](oid_or_name)
|
142
|
+
$og.load(oid_or_name, #{klass})
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.load_all(extra_sql = nil)
|
146
|
+
$og.load_all(#{klass}, extra_sql)
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.all(extra_sql = nil)
|
150
|
+
$og.load_all(#{klass}, extra_sql)
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.count(sql = "SELECT COUNT(*) FROM #{klass::DBTABLE}")
|
154
|
+
$og.count(sql, #{klass})
|
155
|
+
end
|
156
|
+
|
157
|
+
def self.select(sql)
|
158
|
+
$og.select(sql, #{klass})
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.select_one(sql)
|
162
|
+
$og.select_one(sql, #{klass})
|
163
|
+
end
|
164
|
+
|
165
|
+
def self.delete(obj_or_oid)
|
166
|
+
$og.delete(obj_or_oid, #{klass})
|
167
|
+
end
|
168
|
+
|
169
|
+
def save
|
170
|
+
$og << self
|
171
|
+
return self
|
172
|
+
end
|
173
|
+
alias_method :save!, :save
|
174
|
+
|
175
|
+
def update_properties(updatesql)
|
176
|
+
$og.pupdate(updatesql, self.oid, #{klass})
|
177
|
+
end
|
178
|
+
alias_method :pupdate!, :update_properties
|
179
|
+
|
180
|
+
def delete!
|
181
|
+
$og.delete(@oid, #{klass})
|
182
|
+
end
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
# Automatically wrap connection methods.
|
187
|
+
#
|
188
|
+
def self.wrap_method(method, args)
|
189
|
+
args = args.split(/,/)
|
190
|
+
class_eval %{
|
191
|
+
def #{method}(#{args.join(", ")})
|
192
|
+
# nop
|
193
|
+
end
|
194
|
+
}
|
195
|
+
end
|
196
|
+
=begin
|
197
|
+
wrap_method :create_table, "klass"
|
198
|
+
wrap_method :drop_table, "klass"
|
199
|
+
wrap_method :save, "obj"; alias_method :<<, :save; alias_method :put, :save
|
200
|
+
wrap_method :insert, "obj"
|
201
|
+
wrap_method :update, "obj"
|
202
|
+
wrap_method :update_properties, "update_sql, obj_or_oid, klass = nil"
|
203
|
+
wrap_method :pupdate, "update_sql, obj_or_oid, klass = nil"
|
204
|
+
wrap_method :load, "oid, klass"; alias_method :get, :load
|
205
|
+
wrap_method :load_by_oid, "oid, klass"
|
206
|
+
wrap_method :load_by_name, "name, klass"
|
207
|
+
wrap_method :load_all, "klass, extrasql = nil"
|
208
|
+
wrap_method :select, "sql, klass"
|
209
|
+
wrap_method :select_one, "sql, klass"
|
210
|
+
wrap_method :count, "sql, klass = nil"
|
211
|
+
wrap_method :delete, "obj_or_oid, klass = nil"
|
212
|
+
wrap_method :query, "sql"
|
213
|
+
wrap_method :exec, "sql"
|
214
|
+
=end
|
215
|
+
def self.create_db!(config)
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.drop_db!(config)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
end # module
|
223
|
+
|
data/lib/og/version.rb
CHANGED