og 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/CHANGELOG +796 -664
  2. data/INSTALL +24 -24
  3. data/README +39 -32
  4. data/Rakefile +41 -42
  5. data/benchmark/bench.rb +36 -36
  6. data/doc/AUTHORS +15 -12
  7. data/doc/LICENSE +3 -3
  8. data/doc/RELEASES +311 -243
  9. data/doc/config.txt +1 -1
  10. data/examples/mysql_to_psql.rb +15 -15
  11. data/examples/run.rb +92 -92
  12. data/install.rb +7 -17
  13. data/lib/og.rb +76 -75
  14. data/lib/og/collection.rb +203 -160
  15. data/lib/og/entity.rb +168 -169
  16. data/lib/og/errors.rb +5 -5
  17. data/lib/og/manager.rb +179 -178
  18. data/lib/og/mixin/hierarchical.rb +107 -107
  19. data/lib/og/mixin/optimistic_locking.rb +36 -36
  20. data/lib/og/mixin/orderable.rb +148 -148
  21. data/lib/og/mixin/timestamped.rb +8 -8
  22. data/lib/og/mixin/tree.rb +124 -124
  23. data/lib/og/relation.rb +237 -213
  24. data/lib/og/relation/belongs_to.rb +5 -5
  25. data/lib/og/relation/has_many.rb +60 -58
  26. data/lib/og/relation/joins_many.rb +93 -47
  27. data/lib/og/relation/refers_to.rb +25 -21
  28. data/lib/og/store.rb +210 -207
  29. data/lib/og/store/filesys.rb +79 -79
  30. data/lib/og/store/kirby.rb +263 -258
  31. data/lib/og/store/memory.rb +261 -261
  32. data/lib/og/store/mysql.rb +288 -284
  33. data/lib/og/store/psql.rb +261 -244
  34. data/lib/og/store/sql.rb +873 -720
  35. data/lib/og/store/sqlite.rb +177 -175
  36. data/lib/og/store/sqlserver.rb +204 -214
  37. data/lib/og/types.rb +1 -1
  38. data/lib/og/validation.rb +57 -57
  39. data/lib/vendor/mysql.rb +376 -376
  40. data/lib/vendor/mysql411.rb +10 -10
  41. data/test/og/mixin/tc_hierarchical.rb +59 -59
  42. data/test/og/mixin/tc_optimistic_locking.rb +40 -40
  43. data/test/og/mixin/tc_orderable.rb +67 -67
  44. data/test/og/mixin/tc_timestamped.rb +19 -19
  45. data/test/og/store/tc_filesys.rb +46 -46
  46. data/test/og/tc_inheritance.rb +81 -81
  47. data/test/og/tc_join.rb +67 -0
  48. data/test/og/tc_polymorphic.rb +49 -49
  49. data/test/og/tc_relation.rb +57 -30
  50. data/test/og/tc_select.rb +49 -0
  51. data/test/og/tc_store.rb +345 -337
  52. data/test/og/tc_types.rb +11 -11
  53. metadata +11 -18
@@ -16,42 +16,42 @@ end
16
16
  # http://en.wikipedia.org/wiki/Optimistic_concurrency_control
17
17
 
18
18
  module Locking
19
- property :lock_version, Fixnum, :default => 0
20
- pre "@lock_version = 0", :on => :og_insert
21
-
22
- def self.append_features(base) #:nodoc:
23
- PropertyUtils.copy_features(self, base)
24
-
25
- super
26
-
27
- base.module_eval do
28
- def self.enchant
29
- self.send :alias_method, :update_without_lock, :update
30
- self.send :alias_method, :update, :update_with_lock
31
- self.send :alias_method, :save_without_lock, :save
32
- self.send :alias_method, :save, :save_with_lock
33
- end
34
- end
35
- end
36
-
37
- def update_with_lock
38
- lock = @lock_version
39
- @lock_version += 1
40
-
41
- unless update_without_lock(:condition => "lock_version=#{lock}") == 1
42
- raise(StaleObjectError, 'Attempted to update a stale object')
43
- end
44
- end
45
-
46
- def save_with_lock
47
- lock = @lock_version
48
- @lock_version += 1
49
-
50
- unless save_without_lock(:condition => "lock_version=#{lock}") == 1
51
- raise(StaleObjectError, 'Attempted to update a stale object')
52
- end
53
- end
54
-
19
+ property :lock_version, Fixnum, :default => 0
20
+ pre "@lock_version = 0", :on => :og_insert
21
+
22
+ def self.append_features(base) #:nodoc:
23
+ PropertyUtils.copy_features(self, base)
24
+
25
+ super
26
+
27
+ base.module_eval do
28
+ def self.enchant
29
+ self.send :alias_method, :update_without_lock, :update
30
+ self.send :alias_method, :update, :update_with_lock
31
+ self.send :alias_method, :save_without_lock, :save
32
+ self.send :alias_method, :save, :save_with_lock
33
+ end
34
+ end
35
+ end
36
+
37
+ def update_with_lock
38
+ lock = @lock_version
39
+ @lock_version += 1
40
+
41
+ unless update_without_lock(:condition => "lock_version=#{lock}") == 1
42
+ raise(StaleObjectError, 'Attempted to update a stale object')
43
+ end
44
+ end
45
+
46
+ def save_with_lock
47
+ lock = @lock_version
48
+ @lock_version += 1
49
+
50
+ unless save_without_lock(:condition => "lock_version=#{lock}") == 1
51
+ raise(StaleObjectError, 'Attempted to update a stale object')
52
+ end
53
+ end
54
+
55
55
  end
56
56
 
57
57
  end
@@ -6,154 +6,154 @@ module Og
6
6
 
7
7
  module Orderable
8
8
 
9
- def self.append_dynamic_features(base, options)
10
- o = {
11
- :position => 'position',
12
- :type => Fixnum,
13
- }
14
- o.update(options) if options
15
-
16
- if o[:scope].is_a?(Symbol) && o[:scope].to_s !~ /_oid$/
17
- o[:scope] = "#{o[:scope]}_oid".intern
18
- end
19
-
20
- position = o[:position]
21
- scope = o[:scope]
22
-
23
- if scope
24
- if scope.is_a?(Symbol)
25
- scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
26
- end
27
-
28
- cond = 'condition => ' + scope
29
- cond_and = ':condition => ' + scope + ' + " AND " +'
30
- else
31
- cond = ':condition => nil'
32
- cond_and = ':condition => '
33
- end
34
-
35
- code = %{
36
- property :#{position}, #{o[:type]}
37
-
38
- pre "add_to_bottom", :on => :og_insert
39
- pre "decrement_position_of_lower_items", :on => :og_delete
40
-
41
- def move_higher
42
- if higher = higher_item
43
- #{base}.transaction do
44
- higher.increment_position
45
- decrement_position
46
- end
47
- end
48
- end
49
-
50
- def move_lower
51
- if lower = lower_item
52
- #{base}.transaction do
53
- lower.decrement_position
54
- increment_position
55
- end
56
- end
57
- end
58
-
59
- def move_to_top
60
- #{base}.transaction do
61
- increment_position_of_higher_items
62
- set_top_position
63
- end
64
- end
65
-
66
- def move_to_bottom
67
- #{base}.transaction do
68
- decrement_position_of_lower_items
69
- set_bottom_position
70
- end
71
- end
72
-
73
- def move_to
74
- end
75
-
76
- def add_to_top
77
- increment_position_of_all_items
78
- end
79
-
80
- def add_to_bottom
81
- @#{position} = bottom_position + 1
82
- end
83
-
84
- def add_to
85
- end
86
-
87
- def higher_item
88
- #{base}.one(#{cond_and}"#{position}=\#\{@#{position} - 1\}")
89
- end
90
- alias_method :previous_item, :higher_item
91
-
92
- def lower_item
93
- #{base}.one(#{cond_and}"#{position}=\#\{@#{position} + 1\}")
94
- end
95
- alias_method :next_item, :lower_item
96
-
97
- def top_item
98
- end
99
- alias_method :first_item, :top_item
100
-
101
- def bottom_item
102
- #{base}.one(#{cond}, :order => "#{position} DESC", :limit => 1)
103
- end
104
- alias_method :last_item, :last_item
105
-
106
- def top?
107
- @#{position} == 1
108
- end
109
- alias_method :first?, :top?
110
-
111
- def bottom?
112
- @#{position} == bottom_position
113
- end
114
- alias_method :last?, :bottom?
115
-
116
- def increment_position
117
- @#{position} += 1
118
- update(:#{position})
119
- end
120
-
121
- def decrement_position
122
- @#{position} -= 1
123
- update(:#{position})
124
- end
125
-
126
- def bottom_position
127
- item = bottom_item
128
- item ? item.#{position} : 0
129
- end
130
-
131
- def set_top_position
132
- @#{position} = 1
133
- update(:#{position})
134
- end
135
-
136
- def set_bottom_position
137
- @#{position} = bottom_position + 1
138
- update(:#{position})
139
- end
140
-
141
- def increment_position_of_higher_items
142
- #{base}.update_property("#{position}=(#{position} + 1)", #{cond_and}"#{position} < \#\{@#{position}\}")
143
- end
144
-
145
- def increment_position_of_all_items
146
- #{base}.update_property("#{position}=(#{position} + 1)", #{cond})
147
- end
148
-
149
- def decrement_position_of_lower_items
150
- #{base}.update_property("#{position}=(#{position} - 1)", #{cond_and}"#{position} > \#\{@#{position}\}")
151
- end
152
- }
153
-
154
- base.module_eval(code)
155
- end
156
-
9
+ def self.append_dynamic_features(base, options)
10
+ o = {
11
+ :position => 'position',
12
+ :type => Fixnum,
13
+ }
14
+ o.update(options) if options
15
+
16
+ if o[:scope].is_a?(Symbol) && o[:scope].to_s !~ /_oid$/
17
+ o[:scope] = "#{o[:scope]}_oid".intern
18
+ end
19
+
20
+ position = o[:position]
21
+ scope = o[:scope]
22
+
23
+ if scope
24
+ if scope.is_a?(Symbol)
25
+ scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
26
+ end
27
+
28
+ cond = 'condition => ' + scope
29
+ cond_and = ':condition => ' + scope + ' + " AND " +'
30
+ else
31
+ cond = ':condition => nil'
32
+ cond_and = ':condition => '
33
+ end
34
+
35
+ code = %{
36
+ property :#{position}, #{o[:type]}
37
+
38
+ pre "add_to_bottom", :on => :og_insert
39
+ pre "decrement_position_of_lower_items", :on => :og_delete
40
+
41
+ def move_higher
42
+ if higher = higher_item
43
+ #{base}.transaction do
44
+ higher.increment_position
45
+ decrement_position
46
+ end
47
+ end
48
+ end
49
+
50
+ def move_lower
51
+ if lower = lower_item
52
+ #{base}.transaction do
53
+ lower.decrement_position
54
+ increment_position
55
+ end
56
+ end
57
+ end
58
+
59
+ def move_to_top
60
+ #{base}.transaction do
61
+ increment_position_of_higher_items
62
+ set_top_position
63
+ end
64
+ end
65
+
66
+ def move_to_bottom
67
+ #{base}.transaction do
68
+ decrement_position_of_lower_items
69
+ set_bottom_position
70
+ end
71
+ end
72
+
73
+ def move_to
74
+ end
75
+
76
+ def add_to_top
77
+ increment_position_of_all_items
78
+ end
79
+
80
+ def add_to_bottom
81
+ @#{position} = bottom_position + 1
82
+ end
83
+
84
+ def add_to
85
+ end
86
+
87
+ def higher_item
88
+ #{base}.one(#{cond_and}"#{position}=\#\{@#{position} - 1\}")
89
+ end
90
+ alias_method :previous_item, :higher_item
91
+
92
+ def lower_item
93
+ #{base}.one(#{cond_and}"#{position}=\#\{@#{position} + 1\}")
94
+ end
95
+ alias_method :next_item, :lower_item
96
+
97
+ def top_item
98
+ end
99
+ alias_method :first_item, :top_item
100
+
101
+ def bottom_item
102
+ #{base}.one(#{cond}, :order => "#{position} DESC", :limit => 1)
103
+ end
104
+ alias_method :last_item, :last_item
105
+
106
+ def top?
107
+ @#{position} == 1
108
+ end
109
+ alias_method :first?, :top?
110
+
111
+ def bottom?
112
+ @#{position} == bottom_position
113
+ end
114
+ alias_method :last?, :bottom?
115
+
116
+ def increment_position
117
+ @#{position} += 1
118
+ update(:only=>[:#{position}])
119
+ end
120
+
121
+ def decrement_position
122
+ @#{position} -= 1
123
+ update(:only=>[:#{position}])
124
+ end
125
+
126
+ def bottom_position
127
+ item = bottom_item
128
+ item ? item.#{position} : 0
129
+ end
130
+
131
+ def set_top_position
132
+ @#{position} = 1
133
+ update(:only=>[:#{position}])
134
+ end
135
+
136
+ def set_bottom_position
137
+ @#{position} = bottom_position + 1
138
+ update(:only=>[:#{position}])
139
+ end
140
+
141
+ def increment_position_of_higher_items
142
+ #{base}.update_property("#{position}=(#{position} + 1)", #{cond_and}"#{position} < \#\{@#{position}\}")
143
+ end
144
+
145
+ def increment_position_of_all_items
146
+ #{base}.update_property("#{position}=(#{position} + 1)", #{cond})
147
+ end
148
+
149
+ def decrement_position_of_lower_items
150
+ #{base}.update_property("#{position}=(#{position} - 1)", #{cond_and}"#{position} > \#\{@#{position}\}")
151
+ end
152
+ }
153
+
154
+ base.module_eval(code)
155
+ end
156
+
157
157
  end
158
158
 
159
159
  end
@@ -3,16 +3,16 @@ module Og
3
3
  # Adds timestamping functionality.
4
4
 
5
5
  module Timestamped
6
- property :create_time, Time
7
- property :update_time, Time
8
- property :access_time, Time
6
+ property :create_time, Time
7
+ property :update_time, Time
8
+ property :access_time, Time
9
9
 
10
- pre "@create_time = @update_time = Time.now", :on => :og_insert
11
- pre "@update_time = Time.now", :on => :og_update
10
+ pre "@create_time = @update_time = Time.now", :on => :og_insert
11
+ pre "@update_time = Time.now", :on => :og_update
12
12
 
13
- def touch!
14
- @access_time = Time.now
15
- end
13
+ def touch!
14
+ @access_time = Time.now
15
+ end
16
16
  end
17
17
 
18
18
  end
@@ -11,16 +11,16 @@ module Og
11
11
  # article (http://www.dbazine.com/tropashko4.shtml)
12
12
 
13
13
  module TreeTraversal
14
-
15
- # The default prefix for the tree traversal helpers.
16
-
17
- cattr_accessor :prefix, 'tree'
14
+
15
+ # The default prefix for the tree traversal helpers.
16
+
17
+ cattr_accessor :prefix, 'tree'
18
18
 
19
- def self.child(sum, n)
20
- power = 2 ** n
19
+ def self.child(sum, n)
20
+ power = 2 ** n
21
21
 
22
- return sum * power
23
- end
22
+ return sum * power
23
+ end
24
24
 
25
25
  end
26
26
 
@@ -30,15 +30,15 @@ end
30
30
  __END__
31
31
 
32
32
  def xcoord(numer, denom)
33
- num = numer + 1
34
- den = denom * 2
33
+ num = numer + 1
34
+ den = denom * 2
35
35
 
36
- while (num / 2).floor == (num / 2)
37
- num /= 2
38
- den /= 2
39
- end
36
+ while (num / 2).floor == (num / 2)
37
+ num /= 2
38
+ den /= 2
39
+ end
40
40
 
41
- return num, den
41
+ return num, den
42
42
  end
43
43
 
44
44
  #--
@@ -46,111 +46,111 @@ end
46
46
  #++
47
47
 
48
48
  def ycoord(numer, denom)
49
- num, den = xcoord(numer, denom)
49
+ num, den = xcoord(numer, denom)
50
50
 
51
- while den < denom
52
- num *= 2
53
- den *= 2
54
- end
51
+ while den < denom
52
+ num *= 2
53
+ den *= 2
54
+ end
55
55
 
56
- num = numer - num
56
+ num = numer - num
57
57
 
58
- while (num / 2).floor == (num / 2)
59
- num /= 2
60
- den /= 2
61
- end
58
+ while (num / 2).floor == (num / 2)
59
+ num /= 2
60
+ den /= 2
61
+ end
62
62
 
63
- return num, den
63
+ return num, den
64
64
  end
65
65
 
66
66
  def parent(numer, denom)
67
- return nil if numer == 3
67
+ return nil if numer == 3
68
68
 
69
- num = (numer - 1) / 2
70
- den = denom / 2
69
+ num = (numer - 1) / 2
70
+ den = denom / 2
71
71
 
72
- while ((num-1)/4).floor == ((num-1)/4)
73
- num = (num + 1) / 2
74
- den = den / 2
75
- end
76
-
77
- return num, den
72
+ while ((num-1)/4).floor == ((num-1)/4)
73
+ num = (num + 1) / 2
74
+ den = den / 2
75
+ end
76
+
77
+ return num, den
78
78
  end
79
79
 
80
80
  def sibling(numer, denom)
81
- return nil if numer == 3
82
-
83
- num = (numer - 1) / 2
84
- den = denom / 2
85
- sib = 1
86
-
87
- while ((num-1)/4).floor == ((num-1)/4)
88
- return sib if num == 1 and den == 1
89
- num = (num + 1) / 2
90
- den /= 2
91
- sib += 1
92
- end
93
-
94
- return sib
81
+ return nil if numer == 3
82
+
83
+ num = (numer - 1) / 2
84
+ den = denom / 2
85
+ sib = 1
86
+
87
+ while ((num-1)/4).floor == ((num-1)/4)
88
+ return sib if num == 1 and den == 1
89
+ num = (num + 1) / 2
90
+ den /= 2
91
+ sib += 1
92
+ end
93
+
94
+ return sib
95
95
  end
96
96
 
97
97
  def child(numer, denom, n)
98
- power = 2 ** n
98
+ power = 2 ** n
99
99
 
100
- num = (numer * power) + 3 - power
101
- den = denom * power
100
+ num = (numer * power) + 3 - power
101
+ den = denom * power
102
102
 
103
- return num, den
103
+ return num, den
104
104
  end
105
105
 
106
106
  def path(numer, denom)
107
- return '' if numer == nil
108
- n, d = parent(numer, denom)
109
- return "#{path(n, d)}.#{sibling(numer, denom)}"
107
+ return '' if numer == nil
108
+ n, d = parent(numer, denom)
109
+ return "#{path(n, d)}.#{sibling(numer, denom)}"
110
110
  end
111
111
 
112
112
  def encode(path)
113
- num = den = 1
114
- postfix = ".#{path}."
113
+ num = den = 1
114
+ postfix = ".#{path}."
115
115
 
116
- while postfix.length > 1
117
- sibling, postfix = postfix.split('.', 2)
118
- num, den = child(num, den, sibling.to_i)
119
- end
116
+ while postfix.length > 1
117
+ sibling, postfix = postfix.split('.', 2)
118
+ num, den = child(num, den, sibling.to_i)
119
+ end
120
120
 
121
- return num, den
121
+ return num, den
122
122
  end
123
123
 
124
124
 
125
125
  require 'og'
126
126
 
127
127
  class Comment
128
- property :path, String
129
- property :x, :y, Float
128
+ property :path, String
129
+ property :x, :y, Float
130
130
 
131
- def initialize(path = nil, x = nil, y = nil)
132
- @path, @x, @y = path, x, y
133
- end
131
+ def initialize(path = nil, x = nil, y = nil)
132
+ @path, @x, @y = path, x, y
133
+ end
134
134
  end
135
135
 
136
136
  Og::Database.new(
137
- :database => 'test',
138
- :adapter => 'psql',
139
- :user => 'postgres',
140
- :password => 'navelrulez',
141
- :connection_count => 1,
142
- :drop => true
137
+ :database => 'test',
138
+ :adapter => 'psql',
139
+ :user => 'postgres',
140
+ :password => 'navelrulez',
141
+ :connection_count => 1,
142
+ :drop => true
143
143
  )
144
144
 
145
145
  def dp(path)
146
- n, d = encode(path)
147
- n, d = Float(n), Float(d)
148
- # puts "#{path} -> n: #{n} d: #{d} c: #{n/d}"
149
- p = path(n, d)
150
- # puts "=== #{p}"
151
- xn, xd = xcoord(n, d)
152
- yn, yd = ycoord(n, d)
153
- Comment.create(path, xn/xd, yn/yd)
146
+ n, d = encode(path)
147
+ n, d = Float(n), Float(d)
148
+ # puts "#{path} -> n: #{n} d: #{d} c: #{n/d}"
149
+ p = path(n, d)
150
+ # puts "=== #{p}"
151
+ xn, xd = xcoord(n, d)
152
+ yn, yd = ycoord(n, d)
153
+ Comment.create(path, xn/xd, yn/yd)
154
154
  end
155
155
 
156
156
  dp '1.1'
@@ -168,20 +168,20 @@ dp '1.5'
168
168
  dp '1.5.1'
169
169
 
170
170
  for c in Comment.all('ORDER BY x DESC, y ASC')
171
- puts "#{c.path.ljust(16)}#{c.inspect}"
171
+ puts "#{c.path.ljust(16)}#{c.inspect}"
172
172
  end
173
173
 
174
174
  class Article
175
- property :title, :body, String
176
- has_many: :comments, Comment, :tree => true
175
+ property :title, :body, String
176
+ has_many: :comments, Comment, :tree => true
177
177
  end
178
178
 
179
179
  class Comment
180
- property :body, String
181
- belongs_to :article, Article
182
- belongs_to :parent, Comment
183
- has_many :children, Comment, :tree => true
184
- has_many :roles, Role, :list => true
180
+ property :body, String
181
+ belongs_to :article, Article
182
+ belongs_to :parent, Comment
183
+ has_many :children, Comment, :tree => true
184
+ has_many :roles, Role, :list => true
185
185
  end
186
186
 
187
187
 
@@ -190,37 +190,37 @@ comment.add_child(Comment.new('hello'))
190
190
  comment.children_tree
191
191
  comment.children
192
192
 
193
- if options[:tree]
194
- code << %{
195
- property :#{prefix}_x, Fixnum
196
- property :#{prefix}_y, Fixnum
197
- sql_index '#{prefix}_x, #{prefix}_y'
198
- }
199
- end
200
-
201
- if options[:tree]
202
-
203
- code << %{
204
- def #{name}_tree(extrasql = nil)
205
- Og.db.select("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\} ORDER BY #{prefix}_x DESC, #{prefix}_y ASC", #{klass})
206
- end
207
- }
208
-
209
- elsif options[:list]
210
-
211
- else
212
-
213
- end
214
-
215
- }
216
-
217
- if options[:tree]
218
- code << %{
219
- n = Og.db.count("#{linkback}=\#\@oid", #{klass})
220
- ptx = @#{prefix}_x || 0
221
- pty = @#{prefix}_y || 0
222
- obj.#{prefix}_x, obj.#{prefix}_y = TreeTraversal.child(ptx + pty, n)
223
- }
224
- end
225
-
226
- code << %{
193
+ if options[:tree]
194
+ code << %{
195
+ property :#{prefix}_x, Fixnum
196
+ property :#{prefix}_y, Fixnum
197
+ sql_index '#{prefix}_x, #{prefix}_y'
198
+ }
199
+ end
200
+
201
+ if options[:tree]
202
+
203
+ code << %{
204
+ def #{name}_tree(extrasql = nil)
205
+ Og.db.select("SELECT * FROM #{Og::Adapter.table(klass)} WHERE #{linkback}=\#\@oid \#\{extrasql\} ORDER BY #{prefix}_x DESC, #{prefix}_y ASC", #{klass})
206
+ end
207
+ }
208
+
209
+ elsif options[:list]
210
+
211
+ else
212
+
213
+ end
214
+
215
+ }
216
+
217
+ if options[:tree]
218
+ code << %{
219
+ n = Og.db.count("#{linkback}=\#\@oid", #{klass})
220
+ ptx = @#{prefix}_x || 0
221
+ pty = @#{prefix}_y || 0
222
+ obj.#{prefix}_x, obj.#{prefix}_y = TreeTraversal.child(ptx + pty, n)
223
+ }
224
+ end
225
+
226
+ code << %{