og 0.14.0 → 0.15.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.
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: meta.rb 326 2005-03-28 11:07:17Z gmosx $
3
+ # $Id: meta.rb 337 2005-03-31 16:20:40Z gmosx $
4
4
  #--
5
5
  # TODO:
6
6
  # - precreate the meta sql statements as much as possible to
@@ -11,8 +11,6 @@ require 'glue/inflector'
11
11
  require 'og/adapter'
12
12
  require 'og/typemacros'
13
13
 
14
- require 'og/mixins/list'
15
-
16
14
  module Og
17
15
 
18
16
  class Relation < N::Property
@@ -395,7 +393,6 @@ end
395
393
  if Og.include_meta_language
396
394
  class Module # :nodoc: all
397
395
  include Og::MetaLanguage
398
- include Og::List
399
396
  =begin
400
397
  A hack to avoid forward references. Does not work
401
398
  with namespave modules though. Any idea?
@@ -0,0 +1,134 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: hierarchical.rb 341 2005-04-04 08:28:54Z gmosx $
4
+
5
+ require 'glue/dynamic_include'
6
+
7
+ module Og
8
+
9
+ # Implements the Nested Sets pattern for hierarchical
10
+ # SQL queries.
11
+
12
+ module NestedSets
13
+
14
+ def self.append_dynamic_features(base, options)
15
+ c = {
16
+ :left => 'lft',
17
+ :right => 'rgt',
18
+ :type => Fixnum,
19
+ :scope => '"1 = 1"',
20
+ :parent => N::Inflector.name(base),
21
+ :children => N::Inflector.plural_name(base)
22
+ }
23
+ c.update(options) if options
24
+
25
+ parent = "#{c[:parent]}_oid"
26
+ left = c[:left]
27
+ right = c[:right]
28
+ children = c[:children]
29
+ child = N::Inflector.singularize(children)
30
+
31
+ if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
32
+ c[:scope] = "#{c[:scope]}_oid".intern
33
+ end
34
+ scope = c[:scope]
35
+ if scope.is_a?(Symbol)
36
+ scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
37
+ end
38
+
39
+ base.module_eval <<-EOE, __FILE__, __LINE__
40
+ property :#{parent}, Fixnum, :sql_index => true
41
+ property :#{left}, :#{right}, #{c[:type]}
42
+
43
+ def root?
44
+ (@#{parent}.nil? || @#{parent} == 0) && (@#{left} == 1) && (@#{right} > @#{left})
45
+ end
46
+
47
+ def child?
48
+ (@#{parent} && @#{parent} != 0) && (@#{left} > 1) && (@#{right} > @#{left})
49
+ end
50
+
51
+ def #{children}_count
52
+ return (@#{right} - @#{left} - 1)/2
53
+ end
54
+
55
+ def full_#{children}(extrasql = nil)
56
+ #{base}.all("WHERE " + #{scope} + " AND (#{left} BETWEEN \#\{@#{left}\} AND \#{@#{right}}) \#{extrasql}")
57
+ end
58
+
59
+ def #{children}(extrasql = nil)
60
+ #{base}.all("WHERE " + #{scope} + " AND (#{left} > \#\{@#{left}\}) AND (#{right} < \#{@#{right}}) \#{extrasql}")
61
+ end
62
+
63
+ def direct_#{children}(extrasql = nil)
64
+ #{base}.all("WHERE " + #{scope} + " AND #{parent} = \#{@oid} \#{extrasql}")
65
+ end
66
+
67
+ def add_#{child}(child)
68
+ self.reload if @oid
69
+ child.reload if child.oid
70
+
71
+ if @#{left}.nil? || @#{left} == 0 || @#{right}.nil? || @#{right} == 0
72
+ @#{left} = 1
73
+ @#{right} = 2
74
+ end
75
+
76
+ child.#{parent} = @oid
77
+ child.#{left} = pivot = @#{right}
78
+ child.#{right} = pivot + 1
79
+ @#{right} = pivot + 2
80
+
81
+ self.class.transaction do
82
+ self.class.update("#{left} = (#{left} + 2)", "WHERE " + #{scope} + " AND #{left} >= \#{pivot}")
83
+ self.class.update("#{right} = (#{right} + 2)", "WHERE " + #{scope} + " AND #{right} >= \#{pivot}")
84
+ end
85
+
86
+ self.save
87
+ child.save
88
+ 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
+ EOE
102
+ end
103
+
104
+ end
105
+
106
+ # Transform the base class to a hierarchical node.
107
+ # A selection of different implementation strategies
108
+ # are provided.
109
+ #
110
+ # === Example
111
+ #
112
+ # class Comment
113
+ # include Hierarchical, :method => :nested_sets
114
+ # end
115
+ #
116
+ # [+:method+]
117
+ # :simple
118
+ # :nested_sets
119
+ # :nested_intervals
120
+
121
+ module Hierarchical
122
+
123
+ def self.append_dynamic_features(base, options)
124
+ c = {
125
+ :method => :nested_sets,
126
+ }
127
+ c.update(options) if options
128
+
129
+ base.include(NestedSets)
130
+ end
131
+
132
+ end
133
+
134
+ end
@@ -1,24 +1,26 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: list.rb 326 2005-03-28 11:07:17Z gmosx $
3
+ # $Id: orderable.rb 340 2005-04-04 08:26:58Z gmosx $
4
+
5
+ require 'glue/dynamic_include'
4
6
 
5
7
  module Og
6
8
 
7
9
  # Attach list/ordering methods to the enchanted class.
8
- #--
9
- # TODO:
10
- # Convert to new Og filter system.
11
- # Implement as super-mixin.
12
- #++
13
10
 
14
- module List
11
+ module Orderable
15
12
 
16
- # The enchanted object acts as a list item.
13
+ def self.append_dynamic_features(base, options)
14
+ c = {
15
+ :position => 'position',
16
+ :type => Fixnum,
17
+ :scope => '"1 = 1"'
18
+ }
19
+ c.update(options) if options
17
20
 
18
- def acts_as_list(options = {})
19
- c = { :position => 'position', :type => Fixnum, :scope => '1 = 1' }
20
- c.update(options) if options.is_a?(Hash)
21
- c[:scope] = "#{c[:scope]}_oid".intern if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
21
+ if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
22
+ c[:scope] = "#{c[:scope]}_oid".intern
23
+ end
22
24
 
23
25
  position = c[:position]
24
26
  scope = c[:scope]
@@ -27,7 +29,7 @@ module List
27
29
  scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
28
30
  end
29
31
 
30
- module_eval <<-EOE, __FILE__, __LINE__
32
+ base.module_eval <<-EOE, __FILE__, __LINE__
31
33
  property :#{position}, #{c[:type]}
32
34
 
33
35
  def og_pre_insert(conn)
@@ -40,7 +42,7 @@ module List
40
42
 
41
43
  def move_higher
42
44
  if higher = higher_item
43
- #{self}.transaction do
45
+ #{base}.transaction do
44
46
  higher.increment_position
45
47
  decrement_position
46
48
  end
@@ -49,7 +51,7 @@ module List
49
51
 
50
52
  def move_lower
51
53
  if lower = lower_item
52
- #{self}.transaction do
54
+ #{base}.transaction do
53
55
  lower.decrement_position
54
56
  increment_position
55
57
  end
@@ -57,14 +59,14 @@ module List
57
59
  end
58
60
 
59
61
  def move_to_top
60
- #{self}.transaction do
62
+ #{base}.transaction do
61
63
  increment_position_of_higher_items
62
64
  set_top_position
63
65
  end
64
66
  end
65
67
 
66
68
  def move_to_bottom
67
- #{self}.transaction do
69
+ #{base}.transaction do
68
70
  decrement_position_of_lower_items
69
71
  set_bottom_position
70
72
  end
@@ -85,12 +87,12 @@ module List
85
87
  end
86
88
 
87
89
  def higher_item
88
- #{self}.one(#{scope} + " AND #{position}=\#\{@#{position} - 1\}")
90
+ #{base}.one(#{scope} + " AND #{position}=\#\{@#{position} - 1\}")
89
91
  end
90
92
  alias_method :previous_item, :higher_item
91
93
 
92
94
  def lower_item
93
- #{self}.one(#{scope} + " AND #{position}=\#\{@#{position} + 1\}")
95
+ #{base}.one(#{scope} + " AND #{position}=\#\{@#{position} + 1\}")
94
96
  end
95
97
  alias_method :next_item, :lower_item
96
98
 
@@ -99,7 +101,7 @@ module List
99
101
  alias_method :first_item, :top_item
100
102
 
101
103
  def bottom_item
102
- #{self}.one(#{scope} + " ORDER BY #{position} DESC")
104
+ #{base}.one(#{scope} + " ORDER BY #{position} DESC")
103
105
  end
104
106
  alias_method :last_item, :last_item
105
107
 
@@ -139,15 +141,15 @@ module List
139
141
  end
140
142
 
141
143
  def increment_position_of_higher_items
142
- #{self}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope} + " AND #{position} < \#\{@#{position}\}")
144
+ #{base}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope} + " AND #{position} < \#\{@#{position}\}")
143
145
  end
144
146
 
145
147
  def increment_position_of_all_items
146
- #{self}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope})
148
+ #{base}.update("#{position}=(#{position} + 1)", "WHERE " + #{scope})
147
149
  end
148
150
 
149
151
  def decrement_position_of_lower_items
150
- #{self}.update("#{position}=(#{position} - 1)", "WHERE " + #{scope} + " AND #{position} > \#\{@#{position}\}")
152
+ #{base}.update("#{position}=(#{position} - 1)", "WHERE " + #{scope} + " AND #{position} > \#\{@#{position}\}")
151
153
  end
152
154
  EOE
153
155
  end
@@ -1,6 +1,7 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
+ # * Michael Neumann <mneumann@ntecs.de>
2
3
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: typemacros.rb 281 2005-03-10 12:24:14Z gmosx $
4
+ # $Id: typemacros.rb 340 2005-04-04 08:26:58Z gmosx $
4
5
 
5
6
  module Og
6
7
 
@@ -16,8 +17,8 @@ def VarChar(size)
16
17
  return String, :sql => "VARCHAR(#{size})"
17
18
  end
18
19
 
19
- NotNull = {:sql => "NOT NULL"}.freeze
20
+ NotNull = { :sql => 'NOT NULL' }.freeze
20
21
 
21
- Null = {:sql => "NULL"}.freeze
22
+ Null = { :sql => 'NULL' }.freeze
22
23
 
23
24
  end
@@ -0,0 +1,79 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ require 'test/unit'
4
+ require 'ostruct'
5
+
6
+ require 'og/mixins/hierarchical'
7
+
8
+ require 'og'
9
+
10
+ $og = Og::Database.new(
11
+ :adapter => 'psql',
12
+ :database => 'test',
13
+ :user => 'postgres',
14
+ :password => 'navelrulez',
15
+ :drop => true
16
+ )
17
+
18
+ class TestCaseOgHierarchical < Test::Unit::TestCase # :nodoc: all
19
+ include N
20
+
21
+ class Comment
22
+ property :body, String
23
+ property :create_time, Time
24
+
25
+ include Og::NestedSets
26
+
27
+ def initialize(body = nil)
28
+ @body = body
29
+ @create_time = Time.now
30
+ end
31
+
32
+ def to_s
33
+ sprintf("%3d %3d %s", @lft, @rgt, @body)
34
+ end
35
+ end
36
+
37
+ def test_all
38
+ $og.auto_manage_classes
39
+
40
+ root = Comment.create('root')
41
+ c1 = Comment.new('1')
42
+ root.add_comment(c1)
43
+ c2 = Comment.new('1.1')
44
+ c1.add_comment(c2)
45
+ c3 = Comment.new('1.2')
46
+ c1.add_comment(c3)
47
+ c4 = Comment.new('1.1.1')
48
+ c2.add_comment(c4)
49
+ c5 = Comment.new('1.2.1')
50
+ c3.add_comment(c5)
51
+ c6 = Comment.new('1.1.1.1')
52
+ c4.add_comment(c6)
53
+ c7 = Comment.new('2')
54
+ root.add_comment(c7)
55
+ c8 = Comment.new('3')
56
+ root.add_comment(c8)
57
+ c9 = Comment.new('2.1')
58
+ c7.add_comment(c9)
59
+
60
+ c1.reload
61
+ =begin
62
+ Comment.all("ORDER BY lft, rgt").each { |c|
63
+ puts sprintf("%3d %3d %s", c.lft, c.rgt, c.body)
64
+ # p c
65
+ }
66
+ puts '--1'
67
+ c1.comments("ORDER BY lft, rgt").each { |c| puts c.body }
68
+ puts '--2'
69
+ c1.full_comments("ORDER BY lft, rgt").each { |c| puts c.body }
70
+ puts '--3'
71
+ c1.direct_comments("ORDER BY lft, rgt").each { |c| puts c.body }
72
+ =end
73
+
74
+ assert_equal 6, c1.full_comments.size
75
+ assert_equal 5, c1.comments.size
76
+ assert_equal 2, c1.direct_comments.size
77
+ end
78
+
79
+ end
@@ -3,6 +3,8 @@ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
3
3
  require 'test/unit'
4
4
  require 'ostruct'
5
5
 
6
+ require 'og/mixins/orderable'
7
+
6
8
  require 'og'
7
9
 
8
10
  $og = Og::Database.new(
@@ -13,7 +15,7 @@ $og = Og::Database.new(
13
15
  :drop => true
14
16
  )
15
17
 
16
- class TestCaseOgList < Test::Unit::TestCase # :nodoc: all
18
+ class TestCaseOgOrderable < Test::Unit::TestCase # :nodoc: all
17
19
  include N
18
20
 
19
21
  class Comment; end
@@ -30,8 +32,9 @@ class TestCaseOgList < Test::Unit::TestCase # :nodoc: all
30
32
  class Comment
31
33
  property :body, String
32
34
  belongs_to :article, Article
33
- acts_as_list :scope => :article
34
35
 
36
+ include Og::Orderable, :scope => :article
37
+
35
38
  def initialize(body = nil)
36
39
  @body = body
37
40
  end
@@ -0,0 +1,93 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
2
+
3
+ require 'test/unit'
4
+ require 'ostruct'
5
+
6
+ require 'og'
7
+ #require 'og/adapters/sqlserver'
8
+
9
+ class TC_OgSqlserver < Test::Unit::TestCase # :nodoc: all
10
+ include N
11
+
12
+ # Forward declaration.
13
+
14
+ class Comment; end
15
+
16
+ class Article
17
+ prop_accessor :name, String
18
+ prop_accessor :age, Fixnum
19
+ has_many :comments, Comment
20
+
21
+ def initialize (name = nil, age = nil)
22
+ @name, @age = name, age
23
+ end
24
+ end
25
+
26
+ class Comment
27
+ prop_accessor :text, String
28
+ belongs_to :article, Article
29
+
30
+ def initialize(text = nil)
31
+ @text = text
32
+ end
33
+ end
34
+
35
+ def setup
36
+ config = {
37
+ :adapter => 'sqlserver',
38
+ :address => 'localhost',
39
+ :database => 'test',
40
+ :user => 'sa',
41
+ :password => 'sa',
42
+ :connection_count => 2
43
+ }
44
+
45
+ $DBG = true
46
+
47
+ # Og::Database.drop_db!(config)
48
+ @og = Og::Database.new(config)
49
+ end
50
+
51
+ def teardown
52
+ @og.shutdown
53
+ end
54
+
55
+ def test_all
56
+
57
+ puts Article.all.size
58
+ Article.each {|a| a.delete! }
59
+ puts Article.all.size
60
+
61
+ a = Article.new('gmosx', 30)
62
+ a.save!
63
+
64
+ baseoid = a.oid
65
+
66
+ a1 = Article[baseoid]
67
+
68
+ assert_equal 'gmosx', a1.name
69
+ assert_equal 30, a1.age
70
+ assert_equal baseoid, a1.oid
71
+
72
+ Article.create('drak', 12)
73
+ Article.create('ekarak', 34)
74
+ Article.create('mario', 53)
75
+ Article.create('elathan', 34)
76
+
77
+ articles = Article.all
78
+
79
+ assert_equal 5, articles.size
80
+
81
+ a3 = Article['ekarak']
82
+
83
+ assert_equal 'ekarak', a3.name
84
+
85
+ c1 = Comment.new('a comment')
86
+ c1.save!
87
+ a3.add_comment(c1)
88
+
89
+ a5 = Article['ekarak']
90
+ assert_equal 1, a5.comments.size
91
+ end
92
+
93
+ end