og 0.24.0 → 0.25.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/ProjectInfo +2 -5
- data/README +2 -0
- data/doc/AUTHORS +4 -1
- data/doc/RELEASES +53 -0
- data/examples/run.rb +2 -2
- data/lib/{og/mixin → glue}/hierarchical.rb +19 -19
- data/lib/{og/mixin → glue}/optimistic_locking.rb +1 -1
- data/lib/glue/orderable.rb +235 -0
- data/lib/glue/revisable.rb +2 -0
- data/lib/glue/taggable.rb +176 -0
- data/lib/{og/mixin/taggable.rb → glue/taggable_old.rb} +6 -0
- data/lib/glue/timestamped.rb +37 -0
- data/lib/{og/mixin → glue}/tree.rb +3 -8
- data/lib/og.rb +21 -20
- data/lib/og/collection.rb +15 -1
- data/lib/og/entity.rb +256 -114
- data/lib/og/manager.rb +60 -27
- data/lib/og/{mixin/schema_inheritance_base.rb → markers.rb} +5 -2
- data/lib/og/relation.rb +70 -74
- data/lib/og/relation/belongs_to.rb +5 -3
- data/lib/og/relation/has_many.rb +1 -0
- data/lib/og/relation/joins_many.rb +5 -4
- data/lib/og/store.rb +25 -46
- data/lib/og/store/alpha/filesys.rb +1 -1
- data/lib/og/store/alpha/kirby.rb +30 -30
- data/lib/og/store/alpha/memory.rb +49 -49
- data/lib/og/store/alpha/sqlserver.rb +7 -7
- data/lib/og/store/kirby.rb +38 -38
- data/lib/og/store/mysql.rb +43 -43
- data/lib/og/store/psql.rb +222 -53
- data/lib/og/store/sql.rb +165 -105
- data/lib/og/store/sqlite.rb +29 -25
- data/lib/og/validation.rb +24 -14
- data/lib/{vendor → og/vendor}/README +0 -0
- data/lib/{vendor → og/vendor}/kbserver.rb +1 -1
- data/lib/{vendor → og/vendor}/kirbybase.rb +230 -79
- data/lib/{vendor → og/vendor}/mysql.rb +0 -0
- data/lib/{vendor → og/vendor}/mysql411.rb +0 -0
- data/test/og/mixin/tc_hierarchical.rb +1 -1
- data/test/og/mixin/tc_optimistic_locking.rb +1 -1
- data/test/og/mixin/tc_orderable.rb +1 -1
- data/test/og/mixin/tc_taggable.rb +2 -2
- data/test/og/mixin/tc_timestamped.rb +2 -2
- data/test/og/tc_finder.rb +33 -0
- data/test/og/tc_inheritance.rb +2 -2
- data/test/og/tc_scoped.rb +45 -0
- data/test/og/tc_store.rb +1 -7
- metadata +21 -18
- data/lib/og/mixin/orderable.rb +0 -174
- data/lib/og/mixin/revisable.rb +0 -0
- data/lib/og/mixin/timestamped.rb +0 -24
data/lib/og/manager.rb
CHANGED
@@ -16,7 +16,7 @@ class Manager
|
|
16
16
|
class EntityInfo
|
17
17
|
attr_accessor :klass
|
18
18
|
attr_accessor :enchanted
|
19
|
-
attr_accessor :options
|
19
|
+
attr_accessor :options
|
20
20
|
|
21
21
|
def initialize(klass = nil)
|
22
22
|
@klass = klass
|
@@ -31,7 +31,7 @@ class Manager
|
|
31
31
|
|
32
32
|
# The store used for persistence. This is a virtual field
|
33
33
|
# when running in thread_safe mode.
|
34
|
-
|
34
|
+
|
35
35
|
attr_accessor :store
|
36
36
|
|
37
37
|
# The collection of Entities managed by this manager.
|
@@ -42,30 +42,31 @@ class Manager
|
|
42
42
|
@options = options
|
43
43
|
@entities = {}
|
44
44
|
@pool = Pool.new
|
45
|
-
|
45
|
+
|
46
46
|
@store_class = Store.for_name(options[:store])
|
47
47
|
@store_class.destroy(options) if options[:destroy]
|
48
|
+
@store_class.destroy_tables(options) if options[:destroy_tables]
|
48
49
|
|
49
50
|
if Og.thread_safe
|
50
51
|
(options[:connection_count] || 5).times do
|
51
52
|
@pool << @store_class.new(options)
|
52
|
-
end
|
53
|
+
end
|
53
54
|
else
|
54
55
|
@store = @store_class.new(options)
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
|
-
# Get a store from the pool.
|
59
|
-
|
59
|
+
# Get a store from the pool.
|
60
|
+
|
60
61
|
def get_store
|
61
62
|
if Og.thread_safe
|
62
63
|
thread = Thread.current
|
63
|
-
|
64
|
+
|
64
65
|
unless st = thread[:og_store] and st.is_a?(@store_class)
|
65
66
|
st = @pool.pop()
|
66
67
|
thread[:og_store] = st
|
67
68
|
end
|
68
|
-
|
69
|
+
|
69
70
|
return st
|
70
71
|
else
|
71
72
|
return @store
|
@@ -75,20 +76,20 @@ class Manager
|
|
75
76
|
alias_method :conn, :get_store
|
76
77
|
|
77
78
|
# Return a store to the pool.
|
78
|
-
|
79
|
+
|
79
80
|
def put_store
|
80
81
|
if Og.thread_safe
|
81
82
|
thread = Thread.current
|
82
|
-
|
83
|
+
|
83
84
|
if conn = thread[:og_store]
|
84
85
|
thread[:og_store] = nil
|
85
86
|
return @pool.push(conn)
|
86
87
|
end
|
87
88
|
end
|
88
|
-
end
|
89
|
+
end
|
89
90
|
|
90
91
|
# Resolve polymorphic relations.
|
91
|
-
|
92
|
+
|
92
93
|
def resolve_polymorphic(klass)
|
93
94
|
Relations.resolve_polymorphic(klass)
|
94
95
|
end
|
@@ -100,6 +101,7 @@ class Manager
|
|
100
101
|
|
101
102
|
info = EntityInfo.new(klass)
|
102
103
|
|
104
|
+
# DON'T DO THIS!!!
|
103
105
|
klass.module_eval %{
|
104
106
|
def ==(other)
|
105
107
|
other ? @#{klass.primary_key.symbol} == other.#{klass.primary_key.symbol} : false
|
@@ -108,9 +110,9 @@ class Manager
|
|
108
110
|
|
109
111
|
klass.class.send(:attr_accessor, :ogmanager)
|
110
112
|
klass.instance_variable_set '@ogmanager', self
|
111
|
-
|
112
|
-
Relation.enchant(klass)
|
113
|
-
|
113
|
+
|
114
|
+
Relation.enchant(klass)
|
115
|
+
|
114
116
|
# ensure that the superclass is managed before the
|
115
117
|
# subclass.
|
116
118
|
|
@@ -120,25 +122,32 @@ class Manager
|
|
120
122
|
store.enchant(klass, self); put_store
|
121
123
|
|
122
124
|
# Call special class enchanting code.
|
123
|
-
|
125
|
+
|
124
126
|
klass.enchant if klass.respond_to?(:enchant)
|
125
|
-
|
127
|
+
|
126
128
|
@entities[klass] = info
|
127
129
|
end
|
128
130
|
|
129
131
|
# Is this class manageable by Og?
|
130
|
-
|
132
|
+
|
131
133
|
def manageable?(klass)
|
132
|
-
klass.respond_to?(:properties) and (!klass.properties.empty?) # and klass.ann.
|
134
|
+
klass.respond_to?(:properties) and (!klass.properties.empty?) # and klass.ann.self.polymorphic.nil?
|
133
135
|
end
|
134
136
|
|
135
|
-
# Is the class managed by Og?
|
137
|
+
# Is the class managed by Og?
|
136
138
|
|
137
139
|
def managed?(klass)
|
138
140
|
@entities.include?(klass)
|
139
141
|
end
|
140
142
|
alias_method :entity?, :managed?
|
141
143
|
|
144
|
+
# ==
|
145
|
+
# Returns an array containing all classes managed by this manager.
|
146
|
+
# ==
|
147
|
+
def managed_classes
|
148
|
+
@entities.map {|e| e[0]}
|
149
|
+
end
|
150
|
+
|
142
151
|
# Use Ruby's advanced reflection features to find
|
143
152
|
# all manageable classes. Managable are all classes that
|
144
153
|
# define Properties.
|
@@ -156,34 +165,58 @@ class Manager
|
|
156
165
|
end
|
157
166
|
|
158
167
|
# Manage a collection of classes.
|
159
|
-
|
168
|
+
|
160
169
|
def manage_classes(*classes)
|
161
170
|
classes = manageable_classes.flatten # if classes.empty? FIXME!
|
162
|
-
|
171
|
+
|
163
172
|
classes.each { |c| Relation.resolve_targets(c) }
|
164
173
|
classes.each { |c| Relation.resolve_polymorphic_markers(c) }
|
165
174
|
classes.each { |c| Relation.resolve_polymorphic_relations(c) }
|
166
|
-
|
175
|
+
|
167
176
|
# The polymorpic resolution step creates more manageable classes.
|
168
|
-
|
177
|
+
|
169
178
|
classes = manageable_classes.flatten # if classes.empty? FIXME!
|
170
|
-
|
179
|
+
|
171
180
|
Logger.debug "Og manageable classes: #{classes.inspect}" if $DBG
|
172
|
-
|
181
|
+
|
173
182
|
classes.each { |c| Relation.resolve_targets(c) }
|
174
183
|
classes.each { |c| Relation.resolve_names(c) }
|
175
184
|
classes.each { |c| manage(c) }
|
185
|
+
=begin
|
186
|
+
# gmosx: LETS better investigate this.
|
187
|
+
|
188
|
+
# Checks for obsolete tables lying around in the og store.
|
189
|
+
# rp: this shouldn't really be here but I can't think of a better
|
190
|
+
# way to add this functionality.
|
191
|
+
|
192
|
+
store = get_store()
|
193
|
+
|
194
|
+
if store.respond_to? :unmanaged_tables
|
195
|
+
unmanaged_tables = store.unmanaged_tables(self)
|
196
|
+
unmanaged_tables.each do |table|
|
197
|
+
|
198
|
+
if @options[:evolve_schema] == true and @options[:evolve_schema_purge_tables] == true
|
199
|
+
sql = "DROP TABLE #{table}"
|
200
|
+
Logger.debug "Dropping unmanaged database table #{table}"
|
201
|
+
store.conn.exec(sql)
|
202
|
+
else
|
203
|
+
Logger.info "There is a table within the database named '#{table}' that is not managed by an Og class."
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
=end
|
176
208
|
end
|
177
209
|
alias_method :manage_class, :manage_classes
|
178
210
|
|
179
211
|
def unmanage_classes(*classes)
|
180
212
|
classes = manageable_classes.flatten if classes.empty?
|
181
|
-
|
213
|
+
|
182
214
|
for c in classes
|
183
215
|
@entities.delete_if { |k, v| v.klass == c }
|
184
216
|
end
|
185
217
|
end
|
186
218
|
alias_method :unmanage_class, :unmanage_classes
|
219
|
+
|
187
220
|
end
|
188
221
|
|
189
222
|
end
|
@@ -1,5 +1,10 @@
|
|
1
1
|
module Og
|
2
2
|
|
3
|
+
# Marker module. If included in a class, the Og automanager
|
4
|
+
# ignores this class.
|
5
|
+
|
6
|
+
module Unmanageable; end
|
7
|
+
|
3
8
|
# This is a marker module that denotes that the
|
4
9
|
# base class follows the SingleTableInheritance
|
5
10
|
# pattern. Ie, all the subclasses of the base
|
@@ -8,5 +13,3 @@ module Og
|
|
8
13
|
module SchemaInheritanceBase; end
|
9
14
|
|
10
15
|
end
|
11
|
-
|
12
|
-
# * George Moschovitis <gm@navel.gr>
|
data/lib/og/relation.rb
CHANGED
@@ -6,7 +6,7 @@ require 'mega/annotation'
|
|
6
6
|
|
7
7
|
module Og
|
8
8
|
|
9
|
-
# A relation between Entities.
|
9
|
+
# A relation between Entities.
|
10
10
|
#--
|
11
11
|
# Relations are resolved in multiple passes. First
|
12
12
|
# the relations are logged in :relations...
|
@@ -15,51 +15,51 @@ module Og
|
|
15
15
|
class Relation
|
16
16
|
|
17
17
|
# The parameters of this relation.
|
18
|
-
|
18
|
+
|
19
19
|
attr_accessor :options
|
20
|
-
|
20
|
+
|
21
21
|
# A generalized initialize method for all relations.
|
22
22
|
# Contains common setup code.
|
23
|
-
|
23
|
+
|
24
24
|
def initialize(args, options = {})
|
25
25
|
@options = options
|
26
26
|
@options.update(args.pop) if args.last.is_a?(Hash)
|
27
27
|
|
28
28
|
target_name = if collection
|
29
29
|
:target_plural_name
|
30
|
-
else
|
31
|
-
:target_singular_name
|
30
|
+
else
|
31
|
+
:target_singular_name
|
32
32
|
end
|
33
33
|
|
34
34
|
# Check that all needed options are provided.
|
35
|
-
|
35
|
+
|
36
36
|
if args.empty? or (not (args.last.is_a?(Class) or args.last.is_a?(Symbol)))
|
37
37
|
raise 'Class of target not defined'
|
38
38
|
end
|
39
39
|
|
40
40
|
# Try to set the target class. Checks for class and
|
41
41
|
# class symbol.
|
42
|
-
|
42
|
+
|
43
43
|
if args.last.to_s.capitalized?
|
44
44
|
@options[:target_class] = args.pop
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
# Try to set the target name.
|
48
|
-
|
48
|
+
|
49
49
|
if args.last.is_a? Symbol
|
50
50
|
@options[target_name] = args.pop
|
51
|
-
end
|
52
|
-
|
51
|
+
end
|
52
|
+
|
53
53
|
# Inflect target_class if not provided.
|
54
|
-
|
54
|
+
|
55
55
|
@options[:target_class] ||= @options[target_name].to_s.singular.camelize.intern
|
56
|
-
|
56
|
+
|
57
57
|
# FIXME: this is a hack!
|
58
58
|
# setup() rescue nil
|
59
59
|
end
|
60
60
|
|
61
61
|
# Get an option.
|
62
|
-
|
62
|
+
|
63
63
|
def [](key)
|
64
64
|
@options[key]
|
65
65
|
end
|
@@ -71,26 +71,26 @@ class Relation
|
|
71
71
|
end
|
72
72
|
|
73
73
|
# Is this a polymorphic marker?
|
74
|
-
|
74
|
+
|
75
75
|
def polymorphic_marker?
|
76
|
-
target_class == Object
|
76
|
+
target_class == Object
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
# Is this a polymorphic relation ?
|
80
|
-
|
80
|
+
|
81
81
|
def polymorphic?
|
82
|
-
target_class.ann.
|
82
|
+
target_class.ann.self[:polymorphic]
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
# Resolve a polymorphic target class.
|
86
86
|
# Overrided in subclasses.
|
87
|
-
|
87
|
+
|
88
88
|
def resolve_polymorphic
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
# This method is implemented in subclasses.
|
92
|
-
|
93
|
-
def enchant
|
92
|
+
|
93
|
+
def enchant
|
94
94
|
end
|
95
95
|
|
96
96
|
# Access the hash values as methods.
|
@@ -106,10 +106,10 @@ end
|
|
106
106
|
|
107
107
|
class Relation
|
108
108
|
class << self
|
109
|
-
|
110
|
-
# To avoid forward declarations, references to undefined
|
109
|
+
|
110
|
+
# To avoid forward declarations, references to undefined
|
111
111
|
# (at the time of the creation of the relation) classes are
|
112
|
-
# stored as symbols. These symbols are resolved by this
|
112
|
+
# stored as symbols. These symbols are resolved by this
|
113
113
|
# method.
|
114
114
|
#--
|
115
115
|
# FIXME: do something more elegant here.
|
@@ -154,68 +154,68 @@ class Relation
|
|
154
154
|
def resolve_polymorphic_markers(klass)
|
155
155
|
for r in klass.relations
|
156
156
|
if r.polymorphic_marker?
|
157
|
-
r.owner_class.ann :
|
157
|
+
r.owner_class.ann :self, :polymorphic => r.owner_class
|
158
158
|
end
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
162
|
# Resolve polymorphic relations.
|
163
163
|
# If the target class is polymorphic, create a specialized
|
164
|
-
# version of that class (the target) enclosed in the
|
164
|
+
# version of that class (the target) enclosed in the
|
165
165
|
# owner namespace.
|
166
|
-
#
|
166
|
+
#
|
167
167
|
# For example:
|
168
168
|
#
|
169
169
|
# class Article
|
170
170
|
# has_many Comment
|
171
171
|
# ...
|
172
172
|
# end
|
173
|
-
|
173
|
+
|
174
174
|
def resolve_polymorphic_relations(klass)
|
175
175
|
for r in klass.relations
|
176
176
|
if r.polymorphic?
|
177
|
-
|
177
|
+
|
178
178
|
target_dm = r.target_class.to_s.demodulize
|
179
179
|
r.owner_class.module_eval %{
|
180
180
|
class #{r.owner_class}::#{target_dm} < #{r.target_class}
|
181
181
|
end
|
182
182
|
}
|
183
|
-
|
183
|
+
|
184
184
|
# Replace the target class.
|
185
|
-
|
185
|
+
|
186
186
|
r[:target_class] = eval("#{r.owner_class}::#{target_dm}")
|
187
187
|
end
|
188
|
-
|
188
|
+
|
189
189
|
r.resolve_polymorphic
|
190
190
|
end
|
191
191
|
end
|
192
|
-
|
192
|
+
|
193
193
|
# Resolve the names of the relations.
|
194
|
-
|
194
|
+
|
195
195
|
def resolve_names(klass)
|
196
196
|
for r in klass.relations
|
197
197
|
target_name = if r.collection
|
198
198
|
:target_plural_name
|
199
|
-
else
|
199
|
+
else
|
200
200
|
:target_singular_name
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
# Inflect the relation name.
|
204
|
-
|
204
|
+
|
205
205
|
unless r[target_name]
|
206
206
|
r[target_name] = if r.collection
|
207
207
|
r.target_class.to_s.demodulize.underscore.downcase.plural.intern
|
208
208
|
else
|
209
209
|
r.target_class.to_s.demodulize.underscore.downcase.intern
|
210
|
-
end
|
210
|
+
end
|
211
211
|
end
|
212
|
-
|
213
|
-
r[:name] = r[target_name]
|
212
|
+
|
213
|
+
r[:name] = r[target_name]
|
214
214
|
end
|
215
215
|
end
|
216
|
-
|
217
|
-
# General
|
218
|
-
|
216
|
+
|
217
|
+
# General resolve method.
|
218
|
+
|
219
219
|
def resolve(klass, action = :resolve_polymorphic)
|
220
220
|
for r in klass.relations
|
221
221
|
r.send(action)
|
@@ -223,41 +223,36 @@ class Relation
|
|
223
223
|
end
|
224
224
|
|
225
225
|
# Perform relation enchanting on this class.
|
226
|
-
|
227
|
-
def enchant(klass)
|
226
|
+
|
227
|
+
def enchant(klass)
|
228
228
|
# update inherited relations.
|
229
|
-
|
229
|
+
|
230
230
|
for r in klass.relations
|
231
231
|
r[:owner_class] = klass
|
232
232
|
end
|
233
|
-
|
234
|
-
# enchant.
|
235
|
-
|
233
|
+
|
234
|
+
# enchant.
|
235
|
+
|
236
236
|
for r in klass.relations
|
237
237
|
# p "=== #{klass} : #{r.class} : #{r.name}"
|
238
238
|
r.enchant() unless r.polymorphic_marker?
|
239
239
|
end
|
240
|
-
|
240
|
+
|
241
241
|
end
|
242
|
-
|
242
|
+
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
246
|
-
# Relations domain specific language (DSL). This
|
246
|
+
# Relations domain specific language (DSL). This
|
247
247
|
# language defines macros that are used to define Entity
|
248
|
-
# relations. Additional macros allow for relation
|
248
|
+
# relations. Additional macros allow for relation
|
249
249
|
# inspection.
|
250
250
|
|
251
251
|
module RelationDSL
|
252
|
-
def self.append_features(base)
|
253
|
-
super
|
254
|
-
base.module_eval do
|
255
|
-
inheritor(:relations, [], :+) unless @relations
|
256
|
-
end
|
257
|
-
base.extend(ClassMethods)
|
258
|
-
end
|
259
252
|
|
260
|
-
|
253
|
+
inheritor(:relations, [], :+) #unless @relations
|
254
|
+
|
255
|
+
class_inherit do
|
261
256
|
|
262
257
|
# === Examples
|
263
258
|
#
|
@@ -265,7 +260,7 @@ module RelationDSL
|
|
265
260
|
# belongs_to Article # inflects :article
|
266
261
|
# belongs_to :article, Article
|
267
262
|
# belongs_to :article, Article, :view => 'lala'
|
268
|
-
|
263
|
+
|
269
264
|
def belongs_to(*args)
|
270
265
|
require 'og/relation/belongs_to'
|
271
266
|
relations! << Og::BelongsTo.new(args, :owner_class => self)
|
@@ -275,7 +270,7 @@ module RelationDSL
|
|
275
270
|
#
|
276
271
|
# refers_to :topic # inflects Topic
|
277
272
|
# refers_to Topic # inflects :topic
|
278
|
-
|
273
|
+
|
279
274
|
def refers_to(*args)
|
280
275
|
require 'og/relation/refers_to'
|
281
276
|
relations! << Og::RefersTo.new(args, :owner_class => self)
|
@@ -284,31 +279,31 @@ module RelationDSL
|
|
284
279
|
# === Examples
|
285
280
|
#
|
286
281
|
# has_one User
|
287
|
-
|
282
|
+
|
288
283
|
def has_one(*args)
|
289
284
|
require 'og/relation/has_one'
|
290
285
|
relations! << Og::HasOne.new(args, :owner_class => self)
|
291
286
|
end
|
292
|
-
|
287
|
+
|
293
288
|
# === Examples
|
294
289
|
#
|
295
290
|
# has_many Comment
|
296
291
|
# has_many :comments, Comment
|
297
|
-
|
292
|
+
|
298
293
|
def has_many(*args)
|
299
294
|
require 'og/relation/has_many'
|
300
295
|
relations! << Og::HasMany.new(args, :owner_class => self, :collection => true)
|
301
296
|
end
|
302
297
|
|
303
298
|
# ..
|
304
|
-
|
299
|
+
|
305
300
|
def joins_many(*args)
|
306
301
|
require 'og/relation/joins_many'
|
307
302
|
relations! << Og::JoinsMany.new(args, :owner_class => self, :collection => true)
|
308
303
|
end
|
309
|
-
|
304
|
+
|
310
305
|
# ..
|
311
|
-
|
306
|
+
|
312
307
|
def many_to_many(*args)
|
313
308
|
require 'og/relation/many_to_many'
|
314
309
|
relations! << Og::ManyToMany.new(args, :owner_class => self, :collection => true)
|
@@ -318,8 +313,9 @@ module RelationDSL
|
|
318
313
|
relations.find { |r| r[:name] == name }
|
319
314
|
end
|
320
315
|
alias_method :relation, :inspect_relation
|
321
|
-
|
316
|
+
|
322
317
|
end
|
318
|
+
|
323
319
|
end
|
324
320
|
|
325
321
|
end
|