og 0.16.0 → 0.17.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +485 -0
- data/README +35 -12
- data/Rakefile +4 -7
- data/benchmark/bench.rb +1 -1
- data/doc/AUTHORS +3 -3
- data/doc/RELEASES +153 -2
- data/doc/config.txt +0 -7
- data/doc/tutorial.txt +7 -0
- data/examples/README +5 -0
- data/examples/mysql_to_psql.rb +25 -50
- data/examples/run.rb +62 -77
- data/install.rb +1 -1
- data/lib/og.rb +45 -106
- data/lib/og/collection.rb +156 -0
- data/lib/og/entity.rb +131 -0
- data/lib/og/errors.rb +10 -15
- data/lib/og/manager.rb +115 -0
- data/lib/og/{mixins → mixin}/hierarchical.rb +43 -37
- data/lib/og/{mixins → mixin}/orderable.rb +35 -35
- data/lib/og/{mixins → mixin}/timestamped.rb +0 -6
- data/lib/og/{mixins → mixin}/tree.rb +0 -4
- data/lib/og/relation.rb +178 -0
- data/lib/og/relation/belongs_to.rb +14 -0
- data/lib/og/relation/has_many.rb +62 -0
- data/lib/og/relation/has_one.rb +17 -0
- data/lib/og/relation/joins_many.rb +69 -0
- data/lib/og/relation/many_to_many.rb +17 -0
- data/lib/og/relation/refers_to.rb +31 -0
- data/lib/og/store.rb +223 -0
- data/lib/og/store/filesys.rb +113 -0
- data/lib/og/store/madeleine.rb +4 -0
- data/lib/og/store/memory.rb +291 -0
- data/lib/og/store/mysql.rb +283 -0
- data/lib/og/store/psql.rb +238 -0
- data/lib/og/store/sql.rb +599 -0
- data/lib/og/store/sqlite.rb +190 -0
- data/lib/og/store/sqlserver.rb +262 -0
- data/lib/og/types.rb +19 -0
- data/lib/og/validation.rb +0 -4
- data/test/og/{mixins → mixin}/tc_hierarchical.rb +21 -23
- data/test/og/{mixins → mixin}/tc_orderable.rb +15 -14
- data/test/og/mixin/tc_timestamped.rb +38 -0
- data/test/og/store/tc_filesys.rb +71 -0
- data/test/og/tc_relation.rb +36 -0
- data/test/og/tc_store.rb +290 -0
- data/test/og/tc_types.rb +21 -0
- metadata +54 -40
- data/examples/mock_example.rb +0 -50
- data/lib/og/adapters/base.rb +0 -706
- data/lib/og/adapters/filesys.rb +0 -117
- data/lib/og/adapters/mysql.rb +0 -350
- data/lib/og/adapters/oracle.rb +0 -368
- data/lib/og/adapters/psql.rb +0 -272
- data/lib/og/adapters/sqlite.rb +0 -265
- data/lib/og/adapters/sqlserver.rb +0 -356
- data/lib/og/database.rb +0 -290
- data/lib/og/enchant.rb +0 -149
- data/lib/og/meta.rb +0 -407
- data/lib/og/testing/mock.rb +0 -165
- data/lib/og/typemacros.rb +0 -24
- data/test/og/adapters/tc_filesys.rb +0 -83
- data/test/og/adapters/tc_sqlite.rb +0 -86
- data/test/og/adapters/tc_sqlserver.rb +0 -96
- data/test/og/tc_automanage.rb +0 -46
- data/test/og/tc_lifecycle.rb +0 -105
- data/test/og/tc_many_to_many.rb +0 -61
- data/test/og/tc_meta.rb +0 -55
- data/test/og/tc_validation.rb +0 -89
- data/test/tc_og.rb +0 -364
@@ -0,0 +1,156 @@
|
|
1
|
+
module Og
|
2
|
+
|
3
|
+
# An 'active' collection that reflects a relation.
|
4
|
+
# A collection stores entitities that participate in
|
5
|
+
# a relation.
|
6
|
+
|
7
|
+
class Collection
|
8
|
+
|
9
|
+
# The owner of this collection.
|
10
|
+
|
11
|
+
attr_accessor :owner
|
12
|
+
|
13
|
+
# The members of this collection. Keeps the objects
|
14
|
+
# tha belong to this collection.
|
15
|
+
|
16
|
+
attr_accessor :members
|
17
|
+
|
18
|
+
# A method used to add insert objects in the collection.
|
19
|
+
|
20
|
+
attr_accessor :insert_proc
|
21
|
+
|
22
|
+
# A method used to find the objects that belong to the
|
23
|
+
# collection.
|
24
|
+
|
25
|
+
attr_accessor :find_proc
|
26
|
+
|
27
|
+
# The default find options.
|
28
|
+
|
29
|
+
attr_accessor :find_options
|
30
|
+
|
31
|
+
# Is the collection in build mode?
|
32
|
+
|
33
|
+
attr_accessor :building
|
34
|
+
|
35
|
+
# Is the collection loaded?
|
36
|
+
|
37
|
+
attr_accessor :loaded
|
38
|
+
|
39
|
+
# Initialize the collection.
|
40
|
+
|
41
|
+
def initialize(owner = nil, insert_proc = nil, find_proc = nil, find_options = {})
|
42
|
+
@owner = owner
|
43
|
+
@insert_proc = insert_proc
|
44
|
+
@find_proc = find_proc
|
45
|
+
@find_options = find_options
|
46
|
+
@members = []
|
47
|
+
@loaded = false
|
48
|
+
@building = false
|
49
|
+
end
|
50
|
+
|
51
|
+
# Load the members of the collection.
|
52
|
+
|
53
|
+
def load_members
|
54
|
+
unless @loaded
|
55
|
+
@members = @owner.send(@find_proc, @find_options)
|
56
|
+
@loaded = true
|
57
|
+
end
|
58
|
+
@members
|
59
|
+
end
|
60
|
+
|
61
|
+
# Reload the collection.
|
62
|
+
|
63
|
+
def reload(options)
|
64
|
+
@find_options = options
|
65
|
+
@members = @owner.send(@find_proc, @find_options)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Convert the collection to an array.
|
69
|
+
|
70
|
+
def to_ary
|
71
|
+
load_members
|
72
|
+
@members
|
73
|
+
end
|
74
|
+
|
75
|
+
# Defined to avoid the method missing overhead.
|
76
|
+
|
77
|
+
def each(&block)
|
78
|
+
load_members
|
79
|
+
@members.each(&block)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Defined to avoid the method missing overhead.
|
83
|
+
|
84
|
+
def [](idx)
|
85
|
+
load_members
|
86
|
+
@members[idx]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Add a new member to the collection.
|
90
|
+
|
91
|
+
def push(obj)
|
92
|
+
@members.push(obj)
|
93
|
+
unless @building or owner.unsaved?
|
94
|
+
@owner.send(@insert_proc, obj)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
alias_method :<<, :push
|
98
|
+
alias_method :add, :push
|
99
|
+
|
100
|
+
# Delete a member from the collection.
|
101
|
+
|
102
|
+
def delete(*objects)
|
103
|
+
objects = objects.flatten
|
104
|
+
|
105
|
+
objects.reject! { |obj| @members.delete(obj) if obj.unsaved? }
|
106
|
+
return if objects.empty?
|
107
|
+
|
108
|
+
@owner.transaction do
|
109
|
+
objects.each do |obj|
|
110
|
+
obj.delete
|
111
|
+
@members.delete(obj)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Delete all members of the collection.
|
117
|
+
|
118
|
+
def clear
|
119
|
+
@owner.transaction do
|
120
|
+
@members.each { |obj| obj.delete }
|
121
|
+
end
|
122
|
+
@members.clear
|
123
|
+
end
|
124
|
+
|
125
|
+
# Redirect all other methods to the members array.
|
126
|
+
|
127
|
+
def method_missing(symbol, *args, &block)
|
128
|
+
load_members
|
129
|
+
@members.send(symbol, *args, &block)
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def check_type(obj)
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
__END__
|
142
|
+
|
143
|
+
=== Examples
|
144
|
+
|
145
|
+
article.comments.to_ary
|
146
|
+
|
147
|
+
for article in article.comments
|
148
|
+
end
|
149
|
+
|
150
|
+
blog = Blog.new
|
151
|
+
blog.categories << Category.new
|
152
|
+
blog.categories << Category.new
|
153
|
+
blog.enties << Entry.new
|
154
|
+
blog.save
|
155
|
+
|
156
|
+
blog.categories.unlink(1)
|
data/lib/og/entity.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'og/relation'
|
2
|
+
|
3
|
+
module Og
|
4
|
+
|
5
|
+
# Include this module to classes to make them managable by Og.
|
6
|
+
|
7
|
+
module EntityMixin
|
8
|
+
|
9
|
+
def self.append_features(base)
|
10
|
+
super
|
11
|
+
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
|
14
|
+
base.module_eval <<-end_eval, __FILE__, __LINE__
|
15
|
+
def save
|
16
|
+
self.class.ogmanager.store.save(self)
|
17
|
+
return self
|
18
|
+
end
|
19
|
+
alias_method :save!, :save
|
20
|
+
|
21
|
+
def insert
|
22
|
+
self.class.ogmanager.store.insert(self)
|
23
|
+
return self
|
24
|
+
end
|
25
|
+
|
26
|
+
def update(*properties)
|
27
|
+
properties = nil if properties.empty?
|
28
|
+
self.class.ogmanager.store.update(self, properties)
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_properties(set)
|
32
|
+
self.class.ogmanager.store.update_properties(self, set)
|
33
|
+
end
|
34
|
+
|
35
|
+
def reload
|
36
|
+
self.class.ogmanager.store.reload(self, self.pk)
|
37
|
+
end
|
38
|
+
alias_method :reload!, :reload
|
39
|
+
|
40
|
+
def delete
|
41
|
+
self.class.ogmanager.store.delete(self)
|
42
|
+
end
|
43
|
+
alias_method :delete!, :delete
|
44
|
+
|
45
|
+
def transaction(&block)
|
46
|
+
self.class.ogmanager.store.transaction(&block)
|
47
|
+
end
|
48
|
+
end_eval
|
49
|
+
|
50
|
+
base.send(:include, RelationMacros)
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
def create(*args)
|
55
|
+
obj = self.new(*args)
|
56
|
+
yield(obj) if block_given?
|
57
|
+
ogmanager.store.save(obj)
|
58
|
+
return obj
|
59
|
+
end
|
60
|
+
|
61
|
+
def load(pk)
|
62
|
+
ogmanager.store.load(pk, self)
|
63
|
+
end
|
64
|
+
alias_method :[], :load
|
65
|
+
|
66
|
+
def update_properties(set, options = nil)
|
67
|
+
ogmanager.store.update_properties(self, set, options)
|
68
|
+
end
|
69
|
+
alias_method :pupdate, :update_properties
|
70
|
+
alias_method :update_property, :update_properties
|
71
|
+
alias_method :batch_update, :update_properties
|
72
|
+
|
73
|
+
def find(options = {})
|
74
|
+
options[:class] = self
|
75
|
+
ogmanager.store.find(options)
|
76
|
+
end
|
77
|
+
alias_method :all, :find
|
78
|
+
|
79
|
+
def find_one(options = {})
|
80
|
+
options[:class] = self
|
81
|
+
ogmanager.store.find_one(options)
|
82
|
+
end
|
83
|
+
alias_method :one, :find_one
|
84
|
+
alias_method :first, :find_one
|
85
|
+
|
86
|
+
def count(options = {})
|
87
|
+
options[:class] = self
|
88
|
+
ogmanager.store.count(options)
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete(obj_or_pk)
|
92
|
+
ogmanager.store.delete(obj_or_pk, self)
|
93
|
+
end
|
94
|
+
alias_method :delete!, :delete
|
95
|
+
|
96
|
+
def transaction(&block)
|
97
|
+
ogmanager.store.transaction(&block)
|
98
|
+
end
|
99
|
+
|
100
|
+
def primary_key
|
101
|
+
unless @__meta and @__meta[:primary_key]
|
102
|
+
self.meta :primary_key, Entity.resolve_primary_key(self)
|
103
|
+
end
|
104
|
+
@__meta[:primary_key].flatten
|
105
|
+
end
|
106
|
+
|
107
|
+
def const_missing(sym)
|
108
|
+
return sym
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
# A helper class.
|
115
|
+
|
116
|
+
class Entity
|
117
|
+
class << self
|
118
|
+
def resolve_primary_key(klass)
|
119
|
+
for p in klass.properties
|
120
|
+
if p.meta[:primary_key]
|
121
|
+
return p.symbol, p.klass
|
122
|
+
end
|
123
|
+
end
|
124
|
+
return :oid, Fixnum
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
include EntityMixin
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
data/lib/og/errors.rb
CHANGED
@@ -1,21 +1,16 @@
|
|
1
|
-
#
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: errors.rb 1 2005-04-11 11:04:30Z gmosx $
|
1
|
+
# $Id$
|
4
2
|
|
5
3
|
module Og
|
4
|
+
|
5
|
+
# This exception is thrown when a low level error happens
|
6
|
+
# in the store.
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
#--
|
10
|
-
# TODO: rename adapter_exception to store_exception.
|
11
|
-
#++
|
12
|
-
|
13
|
-
class SqlException < Exception
|
14
|
-
attr_accessor :adapter_exception, :sql
|
8
|
+
class StoreException < Exception
|
9
|
+
attr_accessor :original_exception, :info
|
15
10
|
|
16
|
-
def initialize(
|
17
|
-
@
|
11
|
+
def initialize(original_exception, info = nil)
|
12
|
+
@original_exception, @info = original_exception, info
|
18
13
|
end
|
19
14
|
end
|
20
|
-
|
21
|
-
end
|
15
|
+
|
16
|
+
end
|
data/lib/og/manager.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'og/entity'
|
2
|
+
require 'og/store'
|
3
|
+
|
4
|
+
module Og
|
5
|
+
|
6
|
+
# A Manager defines the relations between entities, ie Objects
|
7
|
+
# managed by Og.
|
8
|
+
|
9
|
+
class Manager
|
10
|
+
|
11
|
+
# Information about an Entity class
|
12
|
+
|
13
|
+
class EntityInfo
|
14
|
+
attr_accessor :klass
|
15
|
+
attr_accessor :enchanted
|
16
|
+
attr_accessor :options
|
17
|
+
|
18
|
+
|
19
|
+
def initialize(klass = nil)
|
20
|
+
@klass = klass
|
21
|
+
@enchanted = false
|
22
|
+
@options = {}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# The configuration options.
|
27
|
+
|
28
|
+
attr_accessor :options
|
29
|
+
|
30
|
+
# The store used for persistence.
|
31
|
+
|
32
|
+
attr_accessor :store
|
33
|
+
|
34
|
+
# The collection of Entities managed by this manager.
|
35
|
+
|
36
|
+
attr_accessor :entities
|
37
|
+
|
38
|
+
def initialize(options)
|
39
|
+
@options = options
|
40
|
+
@entities = {}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Manage a class. Converts the class to an Entity.
|
44
|
+
|
45
|
+
def manage(klass)
|
46
|
+
return if managed?(klass) or klass.ancestors.include?(Unmanageable)
|
47
|
+
|
48
|
+
info = EntityInfo.new(klass)
|
49
|
+
|
50
|
+
klass.module_eval %{
|
51
|
+
def ==(other)
|
52
|
+
@#{klass.primary_key.first} == other.#{klass.primary_key.first}
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
klass.instance_variable_set '@ogmanager', self
|
57
|
+
klass.class.send(:attr_accessor, :ogmanager)
|
58
|
+
|
59
|
+
Relation.enchant(klass)
|
60
|
+
@store.enchant(klass, self)
|
61
|
+
|
62
|
+
@entities[klass] = info
|
63
|
+
end
|
64
|
+
|
65
|
+
# Is the class managed by Og?
|
66
|
+
|
67
|
+
def managed?(klass)
|
68
|
+
@entities.include?(klass)
|
69
|
+
end
|
70
|
+
alias_method :entity?, :managed?
|
71
|
+
|
72
|
+
# Use Ruby's advanced reflection features to find
|
73
|
+
# all manageable classes. Managable are all classes that
|
74
|
+
# define Properties.
|
75
|
+
|
76
|
+
def manageable_classes
|
77
|
+
classes = []
|
78
|
+
|
79
|
+
ObjectSpace.each_object(Class) do |c|
|
80
|
+
if c.respond_to?(:__props) and (!c.__props.empty?)
|
81
|
+
classes << c
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
Logger.debug "Og manageable classes: #{classes.inspect}" if $DBG
|
86
|
+
|
87
|
+
return classes
|
88
|
+
end
|
89
|
+
|
90
|
+
# Manage a collection of classes.
|
91
|
+
|
92
|
+
def manage_classes(*classes)
|
93
|
+
classes = manageable_classes if classes.empty?
|
94
|
+
classes.flatten.each { |c| manage(c) }
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
class << self
|
100
|
+
|
101
|
+
# Helper method, useful to initialize Og.
|
102
|
+
|
103
|
+
def setup(options = {})
|
104
|
+
m = Manager.new(options)
|
105
|
+
store = Store.for_name(options[:store])
|
106
|
+
store.destroy(options) if options[:destroy]
|
107
|
+
m.store = store.new(options)
|
108
|
+
m.manage_classes
|
109
|
+
return m
|
110
|
+
end
|
111
|
+
alias_method :connect, :setup
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'facet/string/plural'
|
2
|
+
require 'facet/string/singular'
|
3
|
+
require 'facet/string/demodulize'
|
4
|
+
require 'facet/string/underscore'
|
4
5
|
|
5
6
|
require 'glue/dynamic_include'
|
6
7
|
|
@@ -8,6 +9,9 @@ module Og
|
|
8
9
|
|
9
10
|
# Implements the Nested Sets pattern for hierarchical
|
10
11
|
# SQL queries.
|
12
|
+
#--
|
13
|
+
# TODO: use actice collections.
|
14
|
+
#++
|
11
15
|
|
12
16
|
module NestedSets
|
13
17
|
|
@@ -16,9 +20,8 @@ module NestedSets
|
|
16
20
|
:left => 'lft',
|
17
21
|
:right => 'rgt',
|
18
22
|
:type => Fixnum,
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:children => Inflector.plural_name(base)
|
23
|
+
:parent => base.to_s.demodulize.underscore.downcase,
|
24
|
+
:children => base.to_s.demodulize.underscore.downcase.plural
|
22
25
|
}
|
23
26
|
c.update(options) if options
|
24
27
|
|
@@ -26,16 +29,26 @@ module NestedSets
|
|
26
29
|
left = c[:left]
|
27
30
|
right = c[:right]
|
28
31
|
children = c[:children]
|
29
|
-
child =
|
32
|
+
child = children.singular
|
30
33
|
|
31
34
|
if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
|
32
35
|
c[:scope] = "#{c[:scope]}_oid".intern
|
33
36
|
end
|
37
|
+
|
34
38
|
scope = c[:scope]
|
35
|
-
if scope.is_a?(Symbol)
|
36
|
-
scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
|
37
|
-
end
|
38
39
|
|
40
|
+
if scope
|
41
|
+
if scope.is_a?(Symbol)
|
42
|
+
scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
|
43
|
+
end
|
44
|
+
|
45
|
+
cond = 'condition => ' + scope
|
46
|
+
cond_and = ':condition => ' + scope + ' + " AND " +'
|
47
|
+
else
|
48
|
+
cond = ':condition => nil'
|
49
|
+
cond_and = ':condition => '
|
50
|
+
end
|
51
|
+
|
39
52
|
base.module_eval <<-EOE, __FILE__, __LINE__
|
40
53
|
property :#{parent}, Fixnum, :sql_index => true
|
41
54
|
property :#{left}, :#{right}, #{c[:type]}
|
@@ -52,52 +65,43 @@ module NestedSets
|
|
52
65
|
return (@#{right} - @#{left} - 1)/2
|
53
66
|
end
|
54
67
|
|
55
|
-
def full_#{children}(
|
56
|
-
|
68
|
+
def full_#{children}(options = {})
|
69
|
+
options.update(#{cond_and}"(#{left} BETWEEN \#\{@#{left}\} AND \#{@#{right}})")
|
70
|
+
#{base}.all(options)
|
57
71
|
end
|
58
72
|
|
59
|
-
def #{children}(
|
60
|
-
|
73
|
+
def #{children}(options = {})
|
74
|
+
options.update(#{cond_and}"(#{left} > \#\{@#{left}\}) AND (#{right} < \#{@#{right}})")
|
75
|
+
#{base}.all(options)
|
61
76
|
end
|
62
77
|
|
63
|
-
def direct_#{children}(
|
64
|
-
|
78
|
+
def direct_#{children}(options = {})
|
79
|
+
options.update(#{cond_and}"#{parent} = \#{pk}")
|
80
|
+
#{base}.all(options)
|
65
81
|
end
|
66
82
|
|
67
83
|
def add_#{child}(child)
|
68
|
-
self.reload if
|
69
|
-
child.reload if child.
|
84
|
+
self.reload if pk
|
85
|
+
child.reload if child.pk
|
70
86
|
|
71
87
|
if @#{left}.nil? || @#{left} == 0 || @#{right}.nil? || @#{right} == 0
|
72
88
|
@#{left} = 1
|
73
89
|
@#{right} = 2
|
74
90
|
end
|
75
91
|
|
76
|
-
child.#{parent} =
|
92
|
+
child.#{parent} = pk
|
77
93
|
child.#{left} = pivot = @#{right}
|
78
94
|
child.#{right} = pivot + 1
|
79
95
|
@#{right} = pivot + 2
|
80
96
|
|
81
|
-
|
82
|
-
|
83
|
-
|
97
|
+
#{base}.transaction do
|
98
|
+
#{base}.update_property("#{left} = (#{left} + 2)", #{cond_and}"#{left} >= \#{pivot}")
|
99
|
+
#{base}.update_property("#{right} = (#{right} + 2)", #{cond_and}"#{right} >= \#{pivot}")
|
84
100
|
end
|
85
101
|
|
86
102
|
self.save
|
87
103
|
child.save
|
88
104
|
end
|
89
|
-
|
90
|
-
def self.og_pre_delete(conn, obj)
|
91
|
-
return unless (obj.#{left} and obj.#{right})
|
92
|
-
|
93
|
-
span = obj.#{right} - obj.#{left} + 1
|
94
|
-
|
95
|
-
(klass = obj.class).transaction do
|
96
|
-
klass.delete(#{scope} + " AND #{left} > \#{obj.#{left}} AND (#{right} < \#{obj.#{right}})")
|
97
|
-
klass.update("#{left} = (#{left} - \#{span})", "WHERE " + #{scope} + " AND #{left} >= \#{obj.#{right}}")
|
98
|
-
klass.update("#{right} = (#{right} - \#{span})", "WHERE " + #{scope} + " AND #{right} >= \#{obj.#{right}}")
|
99
|
-
end
|
100
|
-
end
|
101
105
|
EOE
|
102
106
|
end
|
103
107
|
|
@@ -121,14 +125,16 @@ end
|
|
121
125
|
module Hierarchical
|
122
126
|
|
123
127
|
def self.append_dynamic_features(base, options)
|
124
|
-
|
128
|
+
o = {
|
125
129
|
:method => :nested_sets,
|
126
130
|
}
|
127
|
-
|
131
|
+
o.update(options) if options
|
128
132
|
|
129
|
-
base.include(NestedSets)
|
133
|
+
base.include(NestedSets, o)
|
130
134
|
end
|
131
135
|
|
132
136
|
end
|
133
137
|
|
134
138
|
end
|
139
|
+
|
140
|
+
__END__
|