og 0.21.2 → 0.22.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 +60 -1
- data/README +10 -6
- data/doc/RELEASES +66 -0
- data/lib/og.rb +26 -18
- data/lib/og/entity.rb +37 -8
- data/lib/og/manager.rb +12 -10
- data/lib/og/mixin/timestamped.rb +4 -2
- data/lib/og/relation.rb +0 -1
- data/lib/og/relation/has_many.rb +4 -2
- data/lib/og/relation/refers_to.rb +5 -1
- data/lib/og/store.rb +1 -1
- data/lib/og/store/filesys.rb +1 -4
- data/lib/og/store/kirby.rb +1 -2
- data/lib/og/store/mysql.rb +9 -4
- data/lib/og/store/psql.rb +6 -2
- data/lib/og/store/sql.rb +27 -8
- data/lib/og/store/sqlite.rb +6 -2
- data/lib/og/test.rb +2 -0
- data/lib/og/test/assertions.rb +175 -0
- data/lib/og/test/testcase.rb +57 -0
- data/test/og/store/tc_filesys.rb +3 -3
- data/test/og/tc_multiple.rb +68 -0
- data/test/og/tc_polymorphic.rb +6 -0
- data/test/og/tc_reverse.rb +78 -0
- data/test/og/tc_store.rb +5 -5
- metadata +9 -4
data/CHANGELOG
CHANGED
@@ -1,7 +1,66 @@
|
|
1
|
+
07-08-2005 George Moschovitis <gm@navel.gr>
|
2
|
+
|
3
|
+
* lib/og/entity.rb: fixed schema_inheritance alias.
|
4
|
+
|
5
|
+
* lib/og.rb: updated comments.
|
6
|
+
|
7
|
+
* doc/RELEASES: updated.
|
8
|
+
|
9
|
+
06-08-2005 George Moschovitis <gm@navel.gr>
|
10
|
+
|
11
|
+
* lib/og/entity.rb: helper method.
|
12
|
+
|
13
|
+
* lib/og/manager.rb (#manage_class): alias,
|
14
|
+
(#get_store): fixed bug in thread_safe mode, allows multiple
|
15
|
+
og's to run in thread safe mode.
|
16
|
+
|
17
|
+
* test/og/tc_multiple.rb: implemented.
|
18
|
+
|
19
|
+
05-08-2005 George Moschovitis <gm@navel.gr>
|
20
|
+
|
21
|
+
* lib/og/relation/has_many.rb: support for legacy schemas,
|
22
|
+
:foreign_field option,
|
23
|
+
quote foreign_key values,
|
24
|
+
fixed foreign_field bug.
|
25
|
+
|
26
|
+
* lib/og/relation/refers_to.rb: support for legacy schemas.
|
27
|
+
|
28
|
+
* lib/og/entity.rb (#set_primary_key): also get primary key class,
|
29
|
+
(#og_quote): added.
|
30
|
+
|
31
|
+
04-08-2005 George Moschovitis <gm@navel.gr>
|
32
|
+
|
33
|
+
* lib/og/store/*: use #field_for_property where needed,
|
34
|
+
don't create the oid property if not needed!
|
35
|
+
fixed enchant some more,
|
36
|
+
fixed finder calculation to honour field override.
|
37
|
+
|
38
|
+
* lib/og/store/sql.rb (#table): honour sql_table metadata,
|
39
|
+
(#field_for_property): implemented,
|
40
|
+
(#eval_og_read): updated to handle custom fields.
|
41
|
+
|
42
|
+
* lib/og/entity.rb (#sql_table): added helper [daval],
|
43
|
+
added set_xxx prefix to some helper.
|
44
|
+
|
45
|
+
* test/og/tc_reverse.rb: introduced,
|
46
|
+
Yeah, I got data written to a legacy table.
|
47
|
+
|
48
|
+
* lib/og/test/testcase.rb: introduced,
|
49
|
+
(fixture): implemented,
|
50
|
+
(og_fixture): implemented.
|
51
|
+
|
52
|
+
* lib/og/test/assertions.rb: introduced.
|
53
|
+
|
54
|
+
30-07-2005 George Moschovitis <gm@navel.gr>
|
55
|
+
|
56
|
+
* test/: renamed from testing.
|
57
|
+
|
1
58
|
28-07-2005 George Moschovitis <gm@navel.gr>
|
2
59
|
|
60
|
+
* --- VERSION 0.21.1 ---
|
61
|
+
|
3
62
|
* lib/og/store/psql.rb: custom eval_og_allocate,
|
4
|
-
fixed inheritance
|
63
|
+
fixed inheritance problem.
|
5
64
|
|
6
65
|
* lib/og/store/sql.rb: factored out eval_og_allocate.
|
7
66
|
|
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Og 0.
|
1
|
+
= Og 0.22.0 README
|
2
2
|
|
3
3
|
Og (ObjectGraph) is a powerful and elegant object-relational mapping
|
4
4
|
library. Og manages the lifecycle of Ruby objects and provides
|
@@ -28,21 +28,25 @@ distribution (http://www.nitrohq.com).
|
|
28
28
|
|
29
29
|
The library provides the following features:
|
30
30
|
|
31
|
-
* Object-Relational mapping
|
31
|
+
* Object-Relational mapping, automatically maps standard
|
32
|
+
Ruby objects to sql schemas
|
32
33
|
* Absolutely no configuration files.
|
33
34
|
* Multiple stores (PostgreSQL, MySQL, SQLite, Oraclei, SqlServer, ..).
|
34
|
-
* Supports non SQL stores.
|
35
|
+
* Supports non SQL stores (in-memory, filesystem, ..).
|
36
|
+
* Can 'reverse engineer' legacy database schemase.
|
37
|
+
* Fine-grained or High-level customization of the generated
|
38
|
+
schema.
|
35
39
|
* ActiveRecord-style domain specific language and db synchronized
|
36
40
|
collections.
|
37
41
|
* Transforms resultsets from arbitrary sql queries to Ruby objects.
|
38
|
-
*
|
39
|
-
|
42
|
+
* Independent store for each object class, can support multiple
|
43
|
+
stores in the same application.
|
40
44
|
* Deserialize to Ruby Objects.
|
41
45
|
* Deserialize sql join queries to Ruby Objects.
|
42
46
|
* Eager associations.
|
43
47
|
* Serialize arbitrary ruby object graphs through YAML.
|
44
48
|
* Connection pooling.
|
45
|
-
* Thread safety
|
49
|
+
* Thread safety.
|
46
50
|
* SQL transactions.
|
47
51
|
* Aspect oriented constructs allow interception of lifecycle callbacks.
|
48
52
|
* Transparent support for cascading deletes for all backends.
|
data/doc/RELEASES
CHANGED
@@ -1,3 +1,69 @@
|
|
1
|
+
== Version 0.22.0
|
2
|
+
|
3
|
+
A snapshot of the latest developments. Many requested features
|
4
|
+
where implemented, and many reported bugs fixed.
|
5
|
+
|
6
|
+
* The much requested Og 'reverse mode' is implemented. Og's
|
7
|
+
domain specific language and API is extended to allow fine-grained
|
8
|
+
customization of the schema-to-objects mapping. Og can now handle
|
9
|
+
most of the legacy schemas you can throw at it. Here is an
|
10
|
+
example:
|
11
|
+
|
12
|
+
class User
|
13
|
+
property :name, String, :field => :thename, :uniq => true
|
14
|
+
property :password, String
|
15
|
+
property :age, Fixnum, :field => :age3
|
16
|
+
has_many Comment, :foreign_field => :user
|
17
|
+
set_table :my_users
|
18
|
+
set_primary_key :name, String
|
19
|
+
end
|
20
|
+
|
21
|
+
class Comment
|
22
|
+
property :cid, Fixnum
|
23
|
+
property :body, String
|
24
|
+
belongs_to User, :field => :user
|
25
|
+
set_table :my_comments
|
26
|
+
set_primary_key :cid
|
27
|
+
end
|
28
|
+
|
29
|
+
As you can see, even relation fields can be customized. For
|
30
|
+
higher level customization you can overload methods like #table,
|
31
|
+
#field_for_property etc.
|
32
|
+
|
33
|
+
* Og now handles multiple connections to multiple stores even
|
34
|
+
in thread safe mode. This means you can now have objects serialized
|
35
|
+
in different RDBM systems in the same application. Or you can have
|
36
|
+
some objects managed by an RDBMS store and others by a FAST
|
37
|
+
in-memory store. You can still have relations between objects in
|
38
|
+
different stores. An example:
|
39
|
+
|
40
|
+
mysql = Og.setup(:store => :mysql, ..)
|
41
|
+
psql = Og.setup(:store => :psql, ..)
|
42
|
+
|
43
|
+
class User
|
44
|
+
has_many Comment
|
45
|
+
end
|
46
|
+
|
47
|
+
class Comment
|
48
|
+
belongs_to User
|
49
|
+
end
|
50
|
+
|
51
|
+
mysql.manage_class User
|
52
|
+
psql.manage_class Comment
|
53
|
+
|
54
|
+
user.comments << comment
|
55
|
+
|
56
|
+
* Greatly improved support for testing and test-driven-development.
|
57
|
+
Support for Og fixtures and automatic test database
|
58
|
+
setup is provided. Fixtures can be defined with yml or csv files.
|
59
|
+
|
60
|
+
For an example of the testing infrastructure check out the
|
61
|
+
Spark 0.4.0 sources. Spark is a Wiki powered by Nitro.
|
62
|
+
|
63
|
+
* Many smaller changes and feature implementations that make
|
64
|
+
development with Og so much more pleasurable.
|
65
|
+
|
66
|
+
|
1
67
|
== Version 0.21.2
|
2
68
|
|
3
69
|
This is a bug fix release.
|
data/lib/og.rb
CHANGED
@@ -27,24 +27,32 @@ require 'glue/configuration'
|
|
27
27
|
#
|
28
28
|
# The library provides the following features:
|
29
29
|
#
|
30
|
-
#
|
30
|
+
# * Object-Relational mapping, automatically maps standard
|
31
31
|
# Ruby objects to sql schemas
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
32
|
+
# * Absolutely no configuration files.
|
33
|
+
# * Multiple stores (PostgreSQL, MySQL, SQLite, Oraclei, SqlServer, ..).
|
34
|
+
# * Supports non SQL stores (in-memory, filesystem, ..).
|
35
|
+
# * Can 'reverse engineer' legacy database schemase.
|
36
|
+
# * Fine-grained or High-level customization of the generated
|
37
|
+
# schema.
|
38
|
+
# * ActiveRecord-style domain specific language and db synchronized
|
39
|
+
# collections.
|
40
|
+
# * Transforms resultsets from arbitrary sql queries to Ruby objects.
|
41
|
+
# * Independent store for each object class, can support multiple
|
42
|
+
# stores in the same application.
|
43
|
+
# * Deserialize to Ruby Objects.
|
44
|
+
# * Deserialize sql join queries to Ruby Objects.
|
45
|
+
# * Eager associations.
|
46
|
+
# * Serialize arbitrary ruby object graphs through YAML.
|
47
|
+
# * Connection pooling.
|
48
|
+
# * Thread safety.
|
49
|
+
# * SQL transactions.
|
50
|
+
# * Aspect oriented constructs allow interception of lifecycle callbacks.
|
51
|
+
# * Transparent support for cascading deletes for all backends.
|
52
|
+
# * Hierarchical structures (nested sets)
|
53
|
+
# * Works safely as part of distributed application.
|
54
|
+
# * Optimistic locking.
|
55
|
+
# * Simple implementation.
|
48
56
|
#
|
49
57
|
# === Property Metadata
|
50
58
|
#
|
@@ -75,7 +83,7 @@ module Og
|
|
75
83
|
|
76
84
|
# The version.
|
77
85
|
|
78
|
-
Version = '0.
|
86
|
+
Version = '0.22.0'
|
79
87
|
|
80
88
|
# Library path.
|
81
89
|
|
data/lib/og/entity.rb
CHANGED
@@ -14,7 +14,7 @@ module EntityMixin
|
|
14
14
|
base.module_eval <<-end_eval, __FILE__, __LINE__
|
15
15
|
def save(options = nil)
|
16
16
|
self.class.ogmanager.store.save(self, options)
|
17
|
-
#
|
17
|
+
# return self
|
18
18
|
end
|
19
19
|
alias_method :save!, :save
|
20
20
|
|
@@ -56,6 +56,10 @@ module EntityMixin
|
|
56
56
|
def transaction(&block)
|
57
57
|
self.class.ogmanager.store.transaction(&block)
|
58
58
|
end
|
59
|
+
|
60
|
+
def og_quote(obj)
|
61
|
+
self.class.ogmanager.store.quote(obj)
|
62
|
+
end
|
59
63
|
end_eval
|
60
64
|
|
61
65
|
base.send(:include, RelationMacros)
|
@@ -132,7 +136,13 @@ module EntityMixin
|
|
132
136
|
def transaction(&block)
|
133
137
|
ogmanager.store.transaction(&block)
|
134
138
|
end
|
139
|
+
|
140
|
+
# Return the store (connection) for this class.
|
135
141
|
|
142
|
+
def ogstore
|
143
|
+
ogmanager.store
|
144
|
+
end
|
145
|
+
|
136
146
|
def primary_key
|
137
147
|
unless @__meta and @__meta[:primary_key]
|
138
148
|
self.meta :primary_key, Entity.resolve_primary_key(self)
|
@@ -142,21 +152,37 @@ module EntityMixin
|
|
142
152
|
|
143
153
|
# Set the default find options for this entity.
|
144
154
|
|
145
|
-
def
|
155
|
+
def set_find_options(options)
|
146
156
|
meta :find_options, options
|
147
157
|
end
|
158
|
+
alias_method :find_options, :set_find_options
|
159
|
+
|
160
|
+
# Enable schema inheritance for this Entity class.
|
161
|
+
# The Single Table Inheritance pattern is used.
|
162
|
+
|
163
|
+
def set_schema_inheritance
|
164
|
+
meta :schema_inheritance
|
165
|
+
end
|
166
|
+
alias_method :schema_inheritance, :set_schema_inheritance
|
148
167
|
|
149
168
|
# Set the default order option for this entity.
|
150
169
|
|
151
|
-
def
|
170
|
+
def set_order(order_str)
|
152
171
|
meta :find_options, :order => order_str
|
153
172
|
end
|
173
|
+
alias_method :order, :set_order
|
154
174
|
|
155
|
-
#
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
175
|
+
# Set a custom table name.
|
176
|
+
|
177
|
+
def set_sql_table(table)
|
178
|
+
meta :sql_table, table.to_s
|
179
|
+
end
|
180
|
+
alias_method :set_table, :set_sql_table
|
181
|
+
|
182
|
+
# Set the primary key.
|
183
|
+
|
184
|
+
def set_primary_key(pk, pkclass = Fixnum)
|
185
|
+
meta :primary_key, pk, pkclass
|
160
186
|
end
|
161
187
|
|
162
188
|
# Is this entity a polymorphic parent?
|
@@ -178,6 +204,9 @@ end
|
|
178
204
|
class Entity
|
179
205
|
class << self
|
180
206
|
def resolve_primary_key(klass)
|
207
|
+
if pk = klass.__meta[:primary_key]
|
208
|
+
return pk
|
209
|
+
end
|
181
210
|
for p in klass.properties
|
182
211
|
if p.meta[:primary_key]
|
183
212
|
return p.symbol, p.klass
|
data/lib/og/manager.rb
CHANGED
@@ -40,35 +40,36 @@ class Manager
|
|
40
40
|
@entities = {}
|
41
41
|
@pool = Glue::Pool.new
|
42
42
|
|
43
|
-
store_class = Store.for_name(options[:store])
|
44
|
-
store_class.destroy(options) if options[:destroy]
|
43
|
+
@store_class = Store.for_name(options[:store])
|
44
|
+
@store_class.destroy(options) if options[:destroy]
|
45
45
|
|
46
46
|
if Og.thread_safe
|
47
47
|
(options[:connection_count] || 5).times do
|
48
|
-
@pool << store_class.new(options)
|
48
|
+
@pool << @store_class.new(options)
|
49
49
|
end
|
50
50
|
else
|
51
|
-
@store = store_class.new(options)
|
51
|
+
@store = @store_class.new(options)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
# Get a store from the pool.
|
55
|
+
# Get a store from the pool.
|
56
56
|
|
57
57
|
def get_store
|
58
58
|
if Og.thread_safe
|
59
59
|
thread = Thread.current
|
60
60
|
|
61
|
-
unless
|
62
|
-
|
63
|
-
thread[:og_store] =
|
61
|
+
unless st = thread[:og_store] and st.is_a?(@store_class)
|
62
|
+
st = @pool.pop()
|
63
|
+
thread[:og_store] = st
|
64
64
|
end
|
65
65
|
|
66
|
-
return
|
66
|
+
return st
|
67
67
|
else
|
68
68
|
return @store
|
69
69
|
end
|
70
70
|
end
|
71
71
|
alias_method :store, :get_store
|
72
|
+
alias_method :conn, :get_store
|
72
73
|
|
73
74
|
# Return a store to the pool.
|
74
75
|
|
@@ -111,7 +112,7 @@ class Manager
|
|
111
112
|
# subclass.
|
112
113
|
|
113
114
|
manage(klass.superclass) if has_super?(klass)
|
114
|
-
|
115
|
+
|
115
116
|
klass.module_eval %{
|
116
117
|
def ==(other)
|
117
118
|
other ? @#{klass.primary_key.first} == other.#{klass.primary_key.first} : false
|
@@ -181,6 +182,7 @@ class Manager
|
|
181
182
|
classes.each { |c| Relation.resolve(c, :resolve_options) }
|
182
183
|
classes.each { |c| manage(c) }
|
183
184
|
end
|
185
|
+
alias_method :manage_class, :manage_classes
|
184
186
|
|
185
187
|
end
|
186
188
|
|
data/lib/og/mixin/timestamped.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'glue/aspects'
|
2
|
+
|
1
3
|
module Og
|
2
4
|
|
3
5
|
# Adds timestamping functionality.
|
@@ -7,8 +9,8 @@ module Timestamped
|
|
7
9
|
property :update_time, Time
|
8
10
|
property :access_time, Time
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
before "@create_time = @update_time = Time.now", :on => :og_insert
|
13
|
+
before "@update_time = Time.now", :on => :og_update
|
12
14
|
|
13
15
|
def touch!
|
14
16
|
@access_time = Time.now
|
data/lib/og/relation.rb
CHANGED
@@ -42,7 +42,6 @@ class Relation
|
|
42
42
|
# as a polymorphic parent class.
|
43
43
|
# This class acts as template
|
44
44
|
# to generate customized versions of this class.
|
45
|
-
|
46
45
|
owner_class.meta(:polymorphic, owner_class)
|
47
46
|
elsif target_class.respond_to?(:metadata) and target_class.metadata.polymorphic
|
48
47
|
# If the target class is polymorphic, create a specialized
|
data/lib/og/relation/has_many.rb
CHANGED
@@ -32,6 +32,8 @@ class HasMany < Relation
|
|
32
32
|
self[:owner_singular_name] = owner_class.to_s.demodulize.underscore.downcase
|
33
33
|
self[:target_singular_name] = target_plural_name.to_s.singular
|
34
34
|
self[:foreign_key] = "#{foreign_name || owner_singular_name}_#{owner_pk}"
|
35
|
+
# gmosx: DON'T set self[:foreign_field]
|
36
|
+
foreign_field = self[:foreign_field] || self[:foreign_key]
|
35
37
|
|
36
38
|
owner_class.module_eval %{
|
37
39
|
attr_accessor :#{target_plural_name}
|
@@ -65,7 +67,7 @@ class HasMany < Relation
|
|
65
67
|
|
66
68
|
def find_#{target_plural_name}(options = {})
|
67
69
|
find_options = {
|
68
|
-
:condition => "#{
|
70
|
+
:condition => "#{foreign_field} = \#{og_quote(@#{owner_pk})}"
|
69
71
|
}
|
70
72
|
if options
|
71
73
|
if condition = options.delete(:condition)
|
@@ -77,7 +79,7 @@ class HasMany < Relation
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def count_#{target_plural_name}
|
80
|
-
#{target_class}.count(:condition => "#{
|
82
|
+
#{target_class}.count(:condition => "#{foreign_field} = \#{og_quote(@#{owner_pk})}")
|
81
83
|
end
|
82
84
|
}
|
83
85
|
end
|
@@ -7,9 +7,13 @@ class RefersTo < Relation
|
|
7
7
|
def enchant
|
8
8
|
self[:foreign_key] = "#{foreign_name || target_singular_name}_#{target_pk}"
|
9
9
|
|
10
|
+
if self[:field]
|
11
|
+
field = ", :field => :#{self[:field]}"
|
12
|
+
end
|
13
|
+
|
10
14
|
owner_class.module_eval %{
|
11
15
|
attr_accessor :#{target_singular_name}
|
12
|
-
prop_accessor :#{foreign_key}, #{target_pkclass}
|
16
|
+
prop_accessor :#{foreign_key}, #{target_pkclass}#{field}
|
13
17
|
|
14
18
|
def #{target_singular_name}(reload = false)
|
15
19
|
return nil if @#{foreign_key}.nil?
|
data/lib/og/store.rb
CHANGED
@@ -89,7 +89,7 @@ class Store
|
|
89
89
|
def self.find_by_#{p.symbol}(val, operator = '=', options = {})
|
90
90
|
options.update(
|
91
91
|
:class => #{klass},
|
92
|
-
:condition => "#{p.symbol}\#{operator}\#{ogmanager.store.quote(val)}"
|
92
|
+
:condition => "#{p.meta[:field] || p.symbol}\#{operator}\#{ogmanager.store.quote(val)}"
|
93
93
|
)
|
94
94
|
ogmanager.store.#{finder}(options)
|
95
95
|
end;
|
data/lib/og/store/filesys.rb
CHANGED
@@ -6,7 +6,7 @@ require 'og/store'
|
|
6
6
|
module Og
|
7
7
|
|
8
8
|
# A Store that saves the object on the Filesystem.
|
9
|
-
#
|
9
|
+
# An extension of the Memory store.
|
10
10
|
|
11
11
|
class FilesysStore < Store
|
12
12
|
|
@@ -30,8 +30,6 @@ class FilesysStore < Store
|
|
30
30
|
Logger.error "Cannot destroy '#{name}'"
|
31
31
|
end
|
32
32
|
|
33
|
-
# :section: Misc methods.
|
34
|
-
|
35
33
|
# Initialize a connection to this store.
|
36
34
|
|
37
35
|
def initialize(options)
|
@@ -54,7 +52,6 @@ class FilesysStore < Store
|
|
54
52
|
FileUtils.mkdir_p(path(klass))
|
55
53
|
File.open(spath(klass), 'w') { |f| f << '1' }
|
56
54
|
rescue => ex
|
57
|
-
p ex
|
58
55
|
Logger.error "Cannot create directory to store '#{klass}' classes!"
|
59
56
|
end
|
60
57
|
|
data/lib/og/store/kirby.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
begin
|
2
|
-
require 'lib/
|
2
|
+
require 'lib/vendor/kirbybase'
|
3
3
|
rescue Object => ex
|
4
4
|
Logger.error 'KirbyBase is not installed!'
|
5
5
|
Logger.error ex
|
@@ -282,4 +282,3 @@ end
|
|
282
282
|
end
|
283
283
|
|
284
284
|
# * George Moschovitis <gm@navel.gr>
|
285
|
-
# * Ysabel <deb@isabel.org>
|
data/lib/og/store/mysql.rb
CHANGED
@@ -130,7 +130,11 @@ class MysqlStore < SqlStore
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def enchant(klass, manager)
|
133
|
-
klass.
|
133
|
+
if klass.metadata.primary_key.flatten.first == :oid
|
134
|
+
unless klass.properties.find { |p| p.symbol == :oid }
|
135
|
+
klass.property :oid, Fixnum, :sql => 'integer AUTO_INCREMENT PRIMARY KEY'
|
136
|
+
end
|
137
|
+
end
|
134
138
|
super
|
135
139
|
end
|
136
140
|
|
@@ -183,7 +187,7 @@ private
|
|
183
187
|
|
184
188
|
# Create table constrains.
|
185
189
|
|
186
|
-
if klass.
|
190
|
+
if klass.metadata and constrains = klass.metadata.sql_constrain
|
187
191
|
sql << ", #{constrains.join(', ')}"
|
188
192
|
end
|
189
193
|
|
@@ -293,17 +297,18 @@ private
|
|
293
297
|
def eval_og_insert(klass)
|
294
298
|
props = klass.properties.dup
|
295
299
|
values = props.collect { |p| write_prop(p) }.join(',')
|
296
|
-
|
300
|
+
|
297
301
|
if klass.metadata.superclass or klass.metadata.subclasses
|
298
302
|
props << Property.new(:ogtype, String)
|
299
303
|
values << ", '#{klass}'"
|
300
304
|
end
|
301
305
|
|
302
|
-
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p
|
306
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| field_for_property(p)}.join(',')}) VALUES (#{values})"
|
303
307
|
|
304
308
|
klass.class_eval %{
|
305
309
|
def og_insert(store)
|
306
310
|
#{Aspects.gen_advice_code(:og_insert, klass.advices, :pre) if klass.respond_to?(:advices)}
|
311
|
+
puts "#{sql}"
|
307
312
|
store.conn.query_with_result = false
|
308
313
|
store.conn.query "#{sql}"
|
309
314
|
@#{klass.pk_symbol} = store.conn.insert_id
|
data/lib/og/store/psql.rb
CHANGED
@@ -132,7 +132,11 @@ class PsqlStore < SqlStore
|
|
132
132
|
klass.const_set 'OGSEQ', "#{table(klass)}_oid_seq"
|
133
133
|
end
|
134
134
|
|
135
|
-
klass.
|
135
|
+
if klass.metadata.primary_key.flatten.first == :oid
|
136
|
+
unless klass.properties.find { |p| p.symbol == :oid }
|
137
|
+
klass.property :oid, Fixnum, :sql => 'serial PRIMARY KEY'
|
138
|
+
end
|
139
|
+
end
|
136
140
|
super
|
137
141
|
end
|
138
142
|
|
@@ -278,7 +282,7 @@ private
|
|
278
282
|
values << ", '#{klass}'"
|
279
283
|
end
|
280
284
|
|
281
|
-
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p
|
285
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| field_for_property(p)}.join(',')}) VALUES (#{values})"
|
282
286
|
|
283
287
|
klass.class_eval %{
|
284
288
|
def og_insert(store)
|
data/lib/og/store/sql.rb
CHANGED
@@ -110,7 +110,11 @@ module SqlUtils
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def table(klass)
|
113
|
-
|
113
|
+
if t = klass.metadata.sql_table
|
114
|
+
return t.first
|
115
|
+
else
|
116
|
+
"#{Og.table_prefix}#{tableize(klass)}"
|
117
|
+
end
|
114
118
|
end
|
115
119
|
|
116
120
|
def join_object_ordering(obj1, obj2)
|
@@ -227,8 +231,8 @@ class SqlStore < Store
|
|
227
231
|
def initialize(options)
|
228
232
|
super
|
229
233
|
|
230
|
-
# The default Ruby <-> SQL type mappings, should be valid
|
231
|
-
# RDBM systems.
|
234
|
+
# The default Ruby <-> SQL type mappings, should be valid
|
235
|
+
# for most RDBM systems.
|
232
236
|
|
233
237
|
@typemap = {
|
234
238
|
Integer => 'integer',
|
@@ -483,10 +487,23 @@ private
|
|
483
487
|
raise 'Not implemented'
|
484
488
|
end
|
485
489
|
|
490
|
+
# Drop the sql table where objects of this class are
|
491
|
+
# persisted.
|
492
|
+
|
486
493
|
def drop_table(klass)
|
487
494
|
exec "DROP TABLE #{klass.table}"
|
488
495
|
end
|
489
496
|
|
497
|
+
# Return the field for the given property.
|
498
|
+
|
499
|
+
def field_for_property(property)
|
500
|
+
if f = property.meta[:field]
|
501
|
+
return f.to_s
|
502
|
+
else
|
503
|
+
return property.symbol.to_s
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
490
507
|
# Create the fields that correpsond to the klass properties.
|
491
508
|
# The generated fields array is used in create_table.
|
492
509
|
# If the property has an :sql metadata this overrides the
|
@@ -513,7 +530,7 @@ private
|
|
513
530
|
properties.each do |p|
|
514
531
|
klass.index(p.symbol) if p.meta[:index]
|
515
532
|
|
516
|
-
field = p
|
533
|
+
field = field_for_property(p)
|
517
534
|
|
518
535
|
if p.meta and p.meta[:sql]
|
519
536
|
field << " #{p.meta[:sql]}"
|
@@ -538,7 +555,7 @@ private
|
|
538
555
|
|
539
556
|
return fields
|
540
557
|
end
|
541
|
-
|
558
|
+
|
542
559
|
def type_for_class(klass)
|
543
560
|
@typemap[klass]
|
544
561
|
end
|
@@ -609,7 +626,7 @@ private
|
|
609
626
|
values << ", '#{klass}'"
|
610
627
|
end
|
611
628
|
|
612
|
-
sql = "INSERT INTO #{klass.table} (#{props.collect {|p| p
|
629
|
+
sql = "INSERT INTO #{klass.table} (#{props.collect {|p| field_for_property(p)}.join(',')}) VALUES (#{values})"
|
613
630
|
|
614
631
|
klass.module_eval %{
|
615
632
|
def og_insert(store)
|
@@ -627,7 +644,7 @@ private
|
|
627
644
|
props = klass.properties.reject { |p| pk == p.symbol }
|
628
645
|
|
629
646
|
updates = props.collect { |p|
|
630
|
-
"#{p
|
647
|
+
"#{field_for_property(p)}=#{write_prop(p)}"
|
631
648
|
}
|
632
649
|
|
633
650
|
sql = "UPDATE #{klass::OGTABLE} SET #{updates.join(', ')} WHERE #{pk}=#\{@#{pk}\}"
|
@@ -655,7 +672,9 @@ private
|
|
655
672
|
field_map = create_field_map(klass)
|
656
673
|
|
657
674
|
props.each do |p|
|
658
|
-
|
675
|
+
f = field_for_property(p).intern
|
676
|
+
|
677
|
+
if col = field_map[f]
|
659
678
|
code << "@#{p.symbol} = #{read_prop(p, col)}"
|
660
679
|
end
|
661
680
|
end
|
data/lib/og/store/sqlite.rb
CHANGED
@@ -64,7 +64,11 @@ class SqliteStore < SqlStore
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def enchant(klass, manager)
|
67
|
-
klass.
|
67
|
+
if klass.metadata.primary_key.flatten.first == :oid
|
68
|
+
unless klass.properties.find { |p| p.symbol == :oid }
|
69
|
+
klass.property :oid, Fixnum, :sql => 'integer PRIMARY KEY'
|
70
|
+
end
|
71
|
+
end
|
68
72
|
super
|
69
73
|
end
|
70
74
|
|
@@ -192,7 +196,7 @@ private
|
|
192
196
|
values << ", '#{klass}'"
|
193
197
|
end
|
194
198
|
|
195
|
-
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| p
|
199
|
+
sql = "INSERT INTO #{klass::OGTABLE} (#{props.collect {|p| field_for_property(p)}.join(',')}) VALUES (#{values})"
|
196
200
|
|
197
201
|
klass.class_eval %{
|
198
202
|
def og_insert(store)
|
data/lib/og/test.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/assertions'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
#--
|
6
|
+
# Og related assertions.
|
7
|
+
#++
|
8
|
+
|
9
|
+
module Test::Unit::Assertions
|
10
|
+
|
11
|
+
STATUS_MAP = {
|
12
|
+
:success => 200,
|
13
|
+
:ok => 200,
|
14
|
+
:redirect => 307
|
15
|
+
}
|
16
|
+
|
17
|
+
# :section: General assertions.
|
18
|
+
|
19
|
+
# Check the status of the response.
|
20
|
+
|
21
|
+
def assert_response(options = {})
|
22
|
+
unless options.is_a? Hash
|
23
|
+
options = { :status => options }
|
24
|
+
end
|
25
|
+
msg = options[:msg]
|
26
|
+
if status = options.fetch(:status, :success)
|
27
|
+
status = STATUS_MAP[status] if STATUS_MAP.has_key?(status)
|
28
|
+
assert_status(status, msg)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_status(status, msg)
|
33
|
+
msg = format_msg("Status not '#{status}'", msg)
|
34
|
+
assert_block(msg) { @context.status == status }
|
35
|
+
end
|
36
|
+
|
37
|
+
#--
|
38
|
+
# Compile some helpers.
|
39
|
+
#++
|
40
|
+
|
41
|
+
for m in [:get, :post, :put, :delete, :head]
|
42
|
+
eval %{
|
43
|
+
def assert_#{m}(uri, headers = {}, params = {}, session = nil)
|
44
|
+
#{m}(uri, headers, params, session)
|
45
|
+
assert_response :success
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def assert_output(options = {})
|
51
|
+
msg = options[:msg]
|
52
|
+
if re = options[:match] || options[:contains]
|
53
|
+
assert_output_match(re, msg)
|
54
|
+
end
|
55
|
+
if re = options[:no_match] || options[:contains_no]
|
56
|
+
assert_output_not_match(re, msg)
|
57
|
+
end
|
58
|
+
if content_type = options[:content_type]
|
59
|
+
assert_content_type(content_type, msg)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def assert_output_match(re, msg)
|
64
|
+
msg = format_msg("Rendered output does not match '#{re.source}'", msg)
|
65
|
+
assert_block(msg) { @context.body =~ Regexp.new(re) }
|
66
|
+
end
|
67
|
+
alias_method :assert_output_contains, :assert_output_match
|
68
|
+
|
69
|
+
def assert_output_not_match(re, msg)
|
70
|
+
msg = format_msg("Rendered output matches '#{re.source}'", msg)
|
71
|
+
assert_block(msg) { @context.out =~ Regexp.new(re) }
|
72
|
+
end
|
73
|
+
alias_method :assert_output_contains_not, :assert_output_match
|
74
|
+
|
75
|
+
def assert_content_type(ctype, msg)
|
76
|
+
msg = format_msg("Content type is not '#{ctype}' as expected", msg)
|
77
|
+
assert_block(msg) { @context.content_type == ctype }
|
78
|
+
end
|
79
|
+
|
80
|
+
# :section: Session related assertions.
|
81
|
+
|
82
|
+
def assert_session(options = {})
|
83
|
+
msg = options[:msg]
|
84
|
+
if key = options[:has]
|
85
|
+
assert_session_has(key, msg)
|
86
|
+
end
|
87
|
+
if key = options[:has_no] || options[:no]
|
88
|
+
assert_session_has_no(key, msg)
|
89
|
+
end
|
90
|
+
if key = options[:key] and value = options[:value]
|
91
|
+
assert_session_equal(key, value, msg)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def assert_session_has(key, msg = nil)
|
96
|
+
msg = format_msg("Object '#{key}' not found in session", msg)
|
97
|
+
assert_block(msg) { @context.session[key] }
|
98
|
+
end
|
99
|
+
|
100
|
+
def assert_session_has_no(key, msg = nil)
|
101
|
+
msg = format_msg("Unexpected object '#{key}' found in session", msg)
|
102
|
+
assert_block(msg) { !@context.session[key] }
|
103
|
+
end
|
104
|
+
|
105
|
+
def assert_session_equal(key, value, msg = nil)
|
106
|
+
msg = format_msg("The value of session object '#{key}' is '#{@context.session[key]}' but was expected '#{value}'", msg)
|
107
|
+
assert_block(msg) { @context.session[key] == value }
|
108
|
+
end
|
109
|
+
|
110
|
+
# :section: Cookies related assertions.
|
111
|
+
|
112
|
+
def assert_cookie(options = {})
|
113
|
+
msg = options[:msg]
|
114
|
+
if key = options[:has]
|
115
|
+
assert_cookie_has(key, msg)
|
116
|
+
end
|
117
|
+
if key = options[:has_no] || options[:no]
|
118
|
+
assert_cookie_has_no(key, msg)
|
119
|
+
end
|
120
|
+
if key = options[:key] and value = options[:value]
|
121
|
+
assert_cookie_equal(key, value, msg)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def assert_cookie_has(name, msg = nil)
|
126
|
+
msg = format_msg("Cookie '#{name}' not found", msg)
|
127
|
+
assert_block(msg) { @context.response_cookie(name) }
|
128
|
+
end
|
129
|
+
|
130
|
+
def assert_cookie_has_no(name, msg = nil)
|
131
|
+
msg = format_msg("Unexpected cookie '#{name}' found", msg)
|
132
|
+
assert_block(msg) { !@context.response_cookie(name) }
|
133
|
+
end
|
134
|
+
|
135
|
+
def assert_cookie_equal(name, value, msg = nil)
|
136
|
+
unless cookie = @context.response_cookie(name)
|
137
|
+
msg = format_msg("Cookie '#{name}' not found", msg)
|
138
|
+
assert_block(msg) { false }
|
139
|
+
end
|
140
|
+
msg = format_msg("The value of cookie '#{name}' is '#{cookie.value}' but was expected '#{value}'", msg)
|
141
|
+
assert_block(msg) { cookie.value == value }
|
142
|
+
end
|
143
|
+
|
144
|
+
# :section: Template related assertions.
|
145
|
+
|
146
|
+
# :section: Redirection assertions.
|
147
|
+
|
148
|
+
def assert_redirected(options = {})
|
149
|
+
msg = options[:msg]
|
150
|
+
|
151
|
+
msg = format_msg("No redirection (status = #{@context.status})", msg)
|
152
|
+
assert_block(msg) { @context.redirect? }
|
153
|
+
|
154
|
+
if to = options[:to]
|
155
|
+
msg = format_msg("Not redirected to '#{to}'", msg)
|
156
|
+
assert_block(msg) { @context.response_headers['location'] == "http://#{to}" }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def assert_not_redirected(options = {})
|
161
|
+
msg = options[:msg]
|
162
|
+
msg = format_msg("Unexpected redirection (location = '#{@context.response_headers['location']}')", msg)
|
163
|
+
assert_block(msg) { !@context.redirect? }
|
164
|
+
end
|
165
|
+
|
166
|
+
# :section: Utility methods
|
167
|
+
|
168
|
+
def format_msg(message, extra) # :nodoc:
|
169
|
+
extra += ', ' if extra
|
170
|
+
return "#{extra}#{message}"
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
# * George Moschovitis <gm@navel.gr>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/assertions'
|
3
|
+
|
4
|
+
require 'facet/string/underscore'
|
5
|
+
require 'facet/string/demodulize'
|
6
|
+
require 'facet/string/pluralize'
|
7
|
+
|
8
|
+
require 'glue'
|
9
|
+
require 'glue/fixture'
|
10
|
+
require 'og'
|
11
|
+
require 'og/test/assertions'
|
12
|
+
|
13
|
+
module Test::Unit
|
14
|
+
|
15
|
+
class TestCase
|
16
|
+
|
17
|
+
# Include fixtures in this test case.
|
18
|
+
#--
|
19
|
+
# gmosx: this method should probably be moved to glue.
|
20
|
+
#++
|
21
|
+
|
22
|
+
def fixture(*classes)
|
23
|
+
|
24
|
+
for klass in classes
|
25
|
+
f = Fixture.new(klass)
|
26
|
+
instance_variable_set "@#{klass.to_s.demodulize.underscore.pluralize}", f
|
27
|
+
Fixtures[klass] = f
|
28
|
+
|
29
|
+
# create variables for the fixture objects.
|
30
|
+
|
31
|
+
for name, obj in f
|
32
|
+
instance_variable_set "@#{name}", obj
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# Include fixtures in this test case, and serialize them in
|
39
|
+
# the active Og store.
|
40
|
+
|
41
|
+
def og_fixture(*classes)
|
42
|
+
fixture(*classes)
|
43
|
+
|
44
|
+
for klass in classes
|
45
|
+
f = Fixtures[klass]
|
46
|
+
|
47
|
+
for obj in f.objects
|
48
|
+
obj.save
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
# * George Moschovitis <gm@navel.gr>
|
data/test/og/store/tc_filesys.rb
CHANGED
@@ -40,8 +40,8 @@ class TestCaseOgFilesys < Test::Unit::TestCase # :nodoc: all
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_all
|
43
|
-
# p Comment.
|
44
|
-
# p Article.
|
43
|
+
# p Comment.metadata
|
44
|
+
# p Article.metadata
|
45
45
|
|
46
46
|
a1 = Article.new('Article 1')
|
47
47
|
@og.store.save(a1)
|
@@ -65,7 +65,7 @@ class TestCaseOgFilesys < Test::Unit::TestCase # :nodoc: all
|
|
65
65
|
# a = Article[1]
|
66
66
|
|
67
67
|
@og.store.close
|
68
|
-
|
68
|
+
# @og.store.class.destroy(@og.options)
|
69
69
|
end
|
70
70
|
|
71
71
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
|
3
|
+
$DBG = true
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
require 'og'
|
8
|
+
|
9
|
+
$og1 = Og.setup(
|
10
|
+
:destroy => true,
|
11
|
+
:store => :mysql,
|
12
|
+
:user => 'root',
|
13
|
+
:password => 'navelrulez',
|
14
|
+
:name => 'test'
|
15
|
+
)
|
16
|
+
|
17
|
+
$og2 = Og.setup(
|
18
|
+
:destroy => true,
|
19
|
+
:store => :psql,
|
20
|
+
:user => 'postgres',
|
21
|
+
:password => 'navelrulez',
|
22
|
+
:name => 'test'
|
23
|
+
)
|
24
|
+
|
25
|
+
class TestMultiple < Test::Unit::TestCase # :nodoc: all
|
26
|
+
include Og
|
27
|
+
|
28
|
+
class User
|
29
|
+
property :name, String, :uniq => true
|
30
|
+
has_many Article
|
31
|
+
|
32
|
+
def initialize(name)
|
33
|
+
@name = name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Article
|
38
|
+
property :title, String
|
39
|
+
belongs_to User
|
40
|
+
|
41
|
+
def initialize(title)
|
42
|
+
@title = title
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_all
|
47
|
+
$og1.manage_class Article
|
48
|
+
$og2.manage_class User
|
49
|
+
|
50
|
+
assert Article.ogmanager.store.is_a?(Og::MysqlStore)
|
51
|
+
assert User.ogmanager.store.is_a?(Og::PsqlStore)
|
52
|
+
|
53
|
+
a1 = Article.create('hello')
|
54
|
+
a2 = Article.create('world')
|
55
|
+
|
56
|
+
u = User.create('gmosx')
|
57
|
+
|
58
|
+
assert_equal 2, Article.count
|
59
|
+
|
60
|
+
u.articles << a1
|
61
|
+
u.articles << a2
|
62
|
+
|
63
|
+
gmosx = User.find_by_name('gmosx')
|
64
|
+
assert_equal 2, gmosx.articles.size
|
65
|
+
assert_equal 'hello', gmosx.articles[0].title
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/test/og/tc_polymorphic.rb
CHANGED
@@ -39,9 +39,15 @@ class TC_OgPolymorphic < Test::Unit::TestCase # :nodoc: all
|
|
39
39
|
|
40
40
|
def setup
|
41
41
|
@og = Og.setup(
|
42
|
+
=begin
|
42
43
|
:destroy => true,
|
43
44
|
:store => :sqlite,
|
44
45
|
:name => 'test'
|
46
|
+
=end
|
47
|
+
:store => :mysql,
|
48
|
+
:name => 'testreverse',
|
49
|
+
:user => 'root',
|
50
|
+
:password => 'navelrulez'
|
45
51
|
)
|
46
52
|
end
|
47
53
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
|
3
|
+
$DBG = true
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
require 'og'
|
8
|
+
|
9
|
+
# 'testreverse' is a legacy database schema. Og's advanced
|
10
|
+
# reverse engineering features allows us to map any schema
|
11
|
+
# to our objects.
|
12
|
+
|
13
|
+
$og = Og.setup(
|
14
|
+
:destroy => true,
|
15
|
+
:store => :mysql,
|
16
|
+
:name => 'testreverse',
|
17
|
+
:user => 'root',
|
18
|
+
:password => 'navelrulez'
|
19
|
+
)
|
20
|
+
|
21
|
+
# create a 'legacy' schema.
|
22
|
+
|
23
|
+
$og.store.exec "create table my_users (thename VARCHAR(32) PRIMARY KEY, password TEXT, age3 INTEGER);"
|
24
|
+
$og.store.exec "create table my_comments (cid MEDIUMINT NOT NULL AUTO_INCREMENT, body TEXT, user VARCHAR(32), PRIMARY KEY(cid));"
|
25
|
+
|
26
|
+
class User
|
27
|
+
property :name, String, :field => :thename, :uniq => true
|
28
|
+
property :password, String
|
29
|
+
property :age, Fixnum, :field => :age3
|
30
|
+
has_many Comment, :foreign_field => :user
|
31
|
+
set_table :my_users
|
32
|
+
set_primary_key :name, String
|
33
|
+
|
34
|
+
def initialize(name, password, age)
|
35
|
+
@name, @password, @age = name, password, age
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Comment
|
40
|
+
property :cid, Fixnum
|
41
|
+
property :body, String
|
42
|
+
belongs_to User, :field => :user
|
43
|
+
set_table :my_comments
|
44
|
+
set_primary_key :cid
|
45
|
+
|
46
|
+
def initialize(body)
|
47
|
+
@body = body
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
$og.manage_classes
|
52
|
+
|
53
|
+
class TestReverse < Test::Unit::TestCase # :nodoc: all
|
54
|
+
include Og
|
55
|
+
|
56
|
+
def test_all
|
57
|
+
assert_equal 'my_users', User.table
|
58
|
+
assert_equal 'my_comments', Comment.table
|
59
|
+
|
60
|
+
User.new('gmosx', 'navel', 30).insert
|
61
|
+
User.new('Helen', 'kontesa', 25).insert
|
62
|
+
|
63
|
+
gmosx = User.find_by_name('gmosx')
|
64
|
+
assert_equal 'gmosx', gmosx.name
|
65
|
+
|
66
|
+
helen = User.find_by_age(25).first
|
67
|
+
assert_equal 'Helen', helen.name
|
68
|
+
|
69
|
+
c = Comment.new('hello')
|
70
|
+
c.insert
|
71
|
+
helen.comments << c
|
72
|
+
|
73
|
+
assert_equal 1, helen.comments(:reload => true).size
|
74
|
+
assert_equal 'hello', helen.comments[0].body
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# * George Moschovitis <gm@navel.gr>
|
data/test/og/tc_store.rb
CHANGED
@@ -44,7 +44,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
|
|
44
44
|
class NewArticle < Article
|
45
45
|
property :more_text, String
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
class Comment
|
49
49
|
property :body, String
|
50
50
|
property :hits, Fixnum
|
@@ -103,7 +103,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
|
|
103
103
|
conversions_test
|
104
104
|
end
|
105
105
|
=end
|
106
|
-
|
106
|
+
#=begin
|
107
107
|
def test_mysql
|
108
108
|
@og = Og.setup(
|
109
109
|
:destroy => true,
|
@@ -116,8 +116,8 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
|
|
116
116
|
features_test
|
117
117
|
# conversions_test
|
118
118
|
end
|
119
|
-
|
120
|
-
|
119
|
+
#=end
|
120
|
+
=begin
|
121
121
|
def test_sqlite
|
122
122
|
@og = Og.setup(
|
123
123
|
:destroy => true,
|
@@ -127,7 +127,7 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
|
|
127
127
|
features_test
|
128
128
|
conversions_test
|
129
129
|
end
|
130
|
-
|
130
|
+
=end
|
131
131
|
=begin
|
132
132
|
def test_memory
|
133
133
|
@og = Og.setup(
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: og
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-07
|
6
|
+
version: 0.22.0
|
7
|
+
date: 2005-08-07 00:00:00 +03:00
|
8
8
|
summary: Og (ObjectGraph)
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -60,8 +60,9 @@ files:
|
|
60
60
|
- lib/og/errors.rb
|
61
61
|
- lib/og/store.rb
|
62
62
|
- lib/og/validation.rb
|
63
|
-
- lib/og/testing
|
64
63
|
- lib/og/types.rb
|
64
|
+
- lib/og/test
|
65
|
+
- lib/og/test.rb
|
65
66
|
- lib/og/relation/belongs_to.rb
|
66
67
|
- lib/og/relation/has_many.rb
|
67
68
|
- lib/og/relation/has_one.rb
|
@@ -81,6 +82,8 @@ files:
|
|
81
82
|
- lib/og/store/sqlite.rb
|
82
83
|
- lib/og/store/kirby.rb
|
83
84
|
- lib/og/store/memory.rb
|
85
|
+
- lib/og/test/assertions.rb
|
86
|
+
- lib/og/test/testcase.rb
|
84
87
|
- lib/vendor/mysql411.rb
|
85
88
|
- lib/vendor/mysql.rb
|
86
89
|
- lib/vendor/kirbybase.rb
|
@@ -95,6 +98,8 @@ files:
|
|
95
98
|
- test/og/tc_polymorphic.rb
|
96
99
|
- test/og/tc_join.rb
|
97
100
|
- test/og/tc_select.rb
|
101
|
+
- test/og/tc_reverse.rb
|
102
|
+
- test/og/tc_multiple.rb
|
98
103
|
- test/og/store/tc_filesys.rb
|
99
104
|
- test/og/mixin/tc_hierarchical.rb
|
100
105
|
- test/og/mixin/tc_orderable.rb
|
@@ -124,5 +129,5 @@ dependencies:
|
|
124
129
|
-
|
125
130
|
- "="
|
126
131
|
- !ruby/object:Gem::Version
|
127
|
-
version: 0.
|
132
|
+
version: 0.22.0
|
128
133
|
version:
|