viking-sequel 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. data/CHANGELOG +3134 -0
  2. data/COPYING +19 -0
  3. data/README.rdoc +723 -0
  4. data/Rakefile +193 -0
  5. data/bin/sequel +196 -0
  6. data/doc/advanced_associations.rdoc +644 -0
  7. data/doc/cheat_sheet.rdoc +218 -0
  8. data/doc/dataset_basics.rdoc +106 -0
  9. data/doc/dataset_filtering.rdoc +158 -0
  10. data/doc/opening_databases.rdoc +296 -0
  11. data/doc/prepared_statements.rdoc +104 -0
  12. data/doc/reflection.rdoc +84 -0
  13. data/doc/release_notes/1.0.txt +38 -0
  14. data/doc/release_notes/1.1.txt +143 -0
  15. data/doc/release_notes/1.3.txt +101 -0
  16. data/doc/release_notes/1.4.0.txt +53 -0
  17. data/doc/release_notes/1.5.0.txt +155 -0
  18. data/doc/release_notes/2.0.0.txt +298 -0
  19. data/doc/release_notes/2.1.0.txt +271 -0
  20. data/doc/release_notes/2.10.0.txt +328 -0
  21. data/doc/release_notes/2.11.0.txt +215 -0
  22. data/doc/release_notes/2.12.0.txt +534 -0
  23. data/doc/release_notes/2.2.0.txt +253 -0
  24. data/doc/release_notes/2.3.0.txt +88 -0
  25. data/doc/release_notes/2.4.0.txt +106 -0
  26. data/doc/release_notes/2.5.0.txt +137 -0
  27. data/doc/release_notes/2.6.0.txt +157 -0
  28. data/doc/release_notes/2.7.0.txt +166 -0
  29. data/doc/release_notes/2.8.0.txt +171 -0
  30. data/doc/release_notes/2.9.0.txt +97 -0
  31. data/doc/release_notes/3.0.0.txt +221 -0
  32. data/doc/release_notes/3.1.0.txt +406 -0
  33. data/doc/release_notes/3.10.0.txt +286 -0
  34. data/doc/release_notes/3.2.0.txt +268 -0
  35. data/doc/release_notes/3.3.0.txt +192 -0
  36. data/doc/release_notes/3.4.0.txt +325 -0
  37. data/doc/release_notes/3.5.0.txt +510 -0
  38. data/doc/release_notes/3.6.0.txt +366 -0
  39. data/doc/release_notes/3.7.0.txt +179 -0
  40. data/doc/release_notes/3.8.0.txt +151 -0
  41. data/doc/release_notes/3.9.0.txt +233 -0
  42. data/doc/schema.rdoc +36 -0
  43. data/doc/sharding.rdoc +113 -0
  44. data/doc/virtual_rows.rdoc +205 -0
  45. data/lib/sequel.rb +1 -0
  46. data/lib/sequel/adapters/ado.rb +90 -0
  47. data/lib/sequel/adapters/ado/mssql.rb +30 -0
  48. data/lib/sequel/adapters/amalgalite.rb +176 -0
  49. data/lib/sequel/adapters/db2.rb +139 -0
  50. data/lib/sequel/adapters/dbi.rb +113 -0
  51. data/lib/sequel/adapters/do.rb +188 -0
  52. data/lib/sequel/adapters/do/mysql.rb +49 -0
  53. data/lib/sequel/adapters/do/postgres.rb +91 -0
  54. data/lib/sequel/adapters/do/sqlite.rb +40 -0
  55. data/lib/sequel/adapters/firebird.rb +283 -0
  56. data/lib/sequel/adapters/informix.rb +77 -0
  57. data/lib/sequel/adapters/jdbc.rb +587 -0
  58. data/lib/sequel/adapters/jdbc/as400.rb +58 -0
  59. data/lib/sequel/adapters/jdbc/h2.rb +133 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
  61. data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
  62. data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
  64. data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
  65. data/lib/sequel/adapters/mysql.rb +421 -0
  66. data/lib/sequel/adapters/odbc.rb +143 -0
  67. data/lib/sequel/adapters/odbc/mssql.rb +42 -0
  68. data/lib/sequel/adapters/openbase.rb +64 -0
  69. data/lib/sequel/adapters/oracle.rb +131 -0
  70. data/lib/sequel/adapters/postgres.rb +504 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +490 -0
  72. data/lib/sequel/adapters/shared/mysql.rb +498 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +195 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +830 -0
  75. data/lib/sequel/adapters/shared/progress.rb +44 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +389 -0
  77. data/lib/sequel/adapters/sqlite.rb +224 -0
  78. data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
  79. data/lib/sequel/connection_pool.rb +99 -0
  80. data/lib/sequel/connection_pool/sharded_single.rb +84 -0
  81. data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
  82. data/lib/sequel/connection_pool/single.rb +29 -0
  83. data/lib/sequel/connection_pool/threaded.rb +150 -0
  84. data/lib/sequel/core.rb +293 -0
  85. data/lib/sequel/core_sql.rb +241 -0
  86. data/lib/sequel/database.rb +1079 -0
  87. data/lib/sequel/database/schema_generator.rb +327 -0
  88. data/lib/sequel/database/schema_methods.rb +203 -0
  89. data/lib/sequel/database/schema_sql.rb +320 -0
  90. data/lib/sequel/dataset.rb +32 -0
  91. data/lib/sequel/dataset/actions.rb +441 -0
  92. data/lib/sequel/dataset/features.rb +86 -0
  93. data/lib/sequel/dataset/graph.rb +254 -0
  94. data/lib/sequel/dataset/misc.rb +119 -0
  95. data/lib/sequel/dataset/mutation.rb +64 -0
  96. data/lib/sequel/dataset/prepared_statements.rb +227 -0
  97. data/lib/sequel/dataset/query.rb +709 -0
  98. data/lib/sequel/dataset/sql.rb +996 -0
  99. data/lib/sequel/exceptions.rb +51 -0
  100. data/lib/sequel/extensions/blank.rb +43 -0
  101. data/lib/sequel/extensions/inflector.rb +242 -0
  102. data/lib/sequel/extensions/looser_typecasting.rb +21 -0
  103. data/lib/sequel/extensions/migration.rb +239 -0
  104. data/lib/sequel/extensions/named_timezones.rb +61 -0
  105. data/lib/sequel/extensions/pagination.rb +100 -0
  106. data/lib/sequel/extensions/pretty_table.rb +82 -0
  107. data/lib/sequel/extensions/query.rb +52 -0
  108. data/lib/sequel/extensions/schema_dumper.rb +271 -0
  109. data/lib/sequel/extensions/sql_expr.rb +122 -0
  110. data/lib/sequel/extensions/string_date_time.rb +46 -0
  111. data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
  112. data/lib/sequel/metaprogramming.rb +9 -0
  113. data/lib/sequel/model.rb +120 -0
  114. data/lib/sequel/model/associations.rb +1514 -0
  115. data/lib/sequel/model/base.rb +1069 -0
  116. data/lib/sequel/model/default_inflections.rb +45 -0
  117. data/lib/sequel/model/errors.rb +39 -0
  118. data/lib/sequel/model/exceptions.rb +21 -0
  119. data/lib/sequel/model/inflections.rb +162 -0
  120. data/lib/sequel/model/plugins.rb +70 -0
  121. data/lib/sequel/plugins/active_model.rb +59 -0
  122. data/lib/sequel/plugins/association_dependencies.rb +103 -0
  123. data/lib/sequel/plugins/association_proxies.rb +41 -0
  124. data/lib/sequel/plugins/boolean_readers.rb +53 -0
  125. data/lib/sequel/plugins/caching.rb +141 -0
  126. data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
  127. data/lib/sequel/plugins/composition.rb +138 -0
  128. data/lib/sequel/plugins/force_encoding.rb +72 -0
  129. data/lib/sequel/plugins/hook_class_methods.rb +126 -0
  130. data/lib/sequel/plugins/identity_map.rb +116 -0
  131. data/lib/sequel/plugins/instance_filters.rb +98 -0
  132. data/lib/sequel/plugins/instance_hooks.rb +57 -0
  133. data/lib/sequel/plugins/lazy_attributes.rb +77 -0
  134. data/lib/sequel/plugins/many_through_many.rb +208 -0
  135. data/lib/sequel/plugins/nested_attributes.rb +206 -0
  136. data/lib/sequel/plugins/optimistic_locking.rb +81 -0
  137. data/lib/sequel/plugins/rcte_tree.rb +281 -0
  138. data/lib/sequel/plugins/schema.rb +66 -0
  139. data/lib/sequel/plugins/serialization.rb +166 -0
  140. data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
  141. data/lib/sequel/plugins/subclasses.rb +45 -0
  142. data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
  143. data/lib/sequel/plugins/timestamps.rb +87 -0
  144. data/lib/sequel/plugins/touch.rb +118 -0
  145. data/lib/sequel/plugins/typecast_on_load.rb +72 -0
  146. data/lib/sequel/plugins/validation_class_methods.rb +405 -0
  147. data/lib/sequel/plugins/validation_helpers.rb +223 -0
  148. data/lib/sequel/sql.rb +1020 -0
  149. data/lib/sequel/timezones.rb +161 -0
  150. data/lib/sequel/version.rb +12 -0
  151. data/lib/sequel_core.rb +1 -0
  152. data/lib/sequel_model.rb +1 -0
  153. data/spec/adapters/firebird_spec.rb +407 -0
  154. data/spec/adapters/informix_spec.rb +97 -0
  155. data/spec/adapters/mssql_spec.rb +403 -0
  156. data/spec/adapters/mysql_spec.rb +1019 -0
  157. data/spec/adapters/oracle_spec.rb +286 -0
  158. data/spec/adapters/postgres_spec.rb +969 -0
  159. data/spec/adapters/spec_helper.rb +51 -0
  160. data/spec/adapters/sqlite_spec.rb +432 -0
  161. data/spec/core/connection_pool_spec.rb +808 -0
  162. data/spec/core/core_sql_spec.rb +417 -0
  163. data/spec/core/database_spec.rb +1662 -0
  164. data/spec/core/dataset_spec.rb +3827 -0
  165. data/spec/core/expression_filters_spec.rb +595 -0
  166. data/spec/core/object_graph_spec.rb +296 -0
  167. data/spec/core/schema_generator_spec.rb +159 -0
  168. data/spec/core/schema_spec.rb +830 -0
  169. data/spec/core/spec_helper.rb +56 -0
  170. data/spec/core/version_spec.rb +7 -0
  171. data/spec/extensions/active_model_spec.rb +76 -0
  172. data/spec/extensions/association_dependencies_spec.rb +127 -0
  173. data/spec/extensions/association_proxies_spec.rb +50 -0
  174. data/spec/extensions/blank_spec.rb +67 -0
  175. data/spec/extensions/boolean_readers_spec.rb +92 -0
  176. data/spec/extensions/caching_spec.rb +250 -0
  177. data/spec/extensions/class_table_inheritance_spec.rb +252 -0
  178. data/spec/extensions/composition_spec.rb +194 -0
  179. data/spec/extensions/force_encoding_spec.rb +117 -0
  180. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  181. data/spec/extensions/identity_map_spec.rb +202 -0
  182. data/spec/extensions/inflector_spec.rb +181 -0
  183. data/spec/extensions/instance_filters_spec.rb +55 -0
  184. data/spec/extensions/instance_hooks_spec.rb +133 -0
  185. data/spec/extensions/lazy_attributes_spec.rb +153 -0
  186. data/spec/extensions/looser_typecasting_spec.rb +39 -0
  187. data/spec/extensions/many_through_many_spec.rb +884 -0
  188. data/spec/extensions/migration_spec.rb +332 -0
  189. data/spec/extensions/named_timezones_spec.rb +72 -0
  190. data/spec/extensions/nested_attributes_spec.rb +396 -0
  191. data/spec/extensions/optimistic_locking_spec.rb +100 -0
  192. data/spec/extensions/pagination_spec.rb +99 -0
  193. data/spec/extensions/pretty_table_spec.rb +91 -0
  194. data/spec/extensions/query_spec.rb +85 -0
  195. data/spec/extensions/rcte_tree_spec.rb +205 -0
  196. data/spec/extensions/schema_dumper_spec.rb +357 -0
  197. data/spec/extensions/schema_spec.rb +127 -0
  198. data/spec/extensions/serialization_spec.rb +209 -0
  199. data/spec/extensions/single_table_inheritance_spec.rb +96 -0
  200. data/spec/extensions/spec_helper.rb +91 -0
  201. data/spec/extensions/sql_expr_spec.rb +89 -0
  202. data/spec/extensions/string_date_time_spec.rb +93 -0
  203. data/spec/extensions/subclasses_spec.rb +52 -0
  204. data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
  205. data/spec/extensions/thread_local_timezones_spec.rb +45 -0
  206. data/spec/extensions/timestamps_spec.rb +150 -0
  207. data/spec/extensions/touch_spec.rb +155 -0
  208. data/spec/extensions/typecast_on_load_spec.rb +69 -0
  209. data/spec/extensions/validation_class_methods_spec.rb +984 -0
  210. data/spec/extensions/validation_helpers_spec.rb +438 -0
  211. data/spec/integration/associations_test.rb +281 -0
  212. data/spec/integration/database_test.rb +26 -0
  213. data/spec/integration/dataset_test.rb +963 -0
  214. data/spec/integration/eager_loader_test.rb +734 -0
  215. data/spec/integration/model_test.rb +130 -0
  216. data/spec/integration/plugin_test.rb +814 -0
  217. data/spec/integration/prepared_statement_test.rb +213 -0
  218. data/spec/integration/schema_test.rb +361 -0
  219. data/spec/integration/spec_helper.rb +73 -0
  220. data/spec/integration/timezone_test.rb +55 -0
  221. data/spec/integration/transaction_test.rb +122 -0
  222. data/spec/integration/type_test.rb +96 -0
  223. data/spec/model/association_reflection_spec.rb +175 -0
  224. data/spec/model/associations_spec.rb +2633 -0
  225. data/spec/model/base_spec.rb +418 -0
  226. data/spec/model/dataset_methods_spec.rb +78 -0
  227. data/spec/model/eager_loading_spec.rb +1391 -0
  228. data/spec/model/hooks_spec.rb +240 -0
  229. data/spec/model/inflector_spec.rb +26 -0
  230. data/spec/model/model_spec.rb +593 -0
  231. data/spec/model/plugins_spec.rb +236 -0
  232. data/spec/model/record_spec.rb +1500 -0
  233. data/spec/model/spec_helper.rb +97 -0
  234. data/spec/model/validations_spec.rb +153 -0
  235. data/spec/rcov.opts +6 -0
  236. data/spec/spec_config.rb.example +10 -0
  237. metadata +346 -0
@@ -0,0 +1,100 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "optimistic_locking plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model(:people)) do
6
+ end
7
+ h = {1=>{:id=>1, :name=>'John', :lock_version=>2}}
8
+ lv = @lv = "lock_version"
9
+ @c.dataset.quote_identifiers = false
10
+ @c.dataset.meta_def(:h){h}
11
+ @c.dataset.meta_def(:lv){lv}
12
+ @c.dataset.meta_def(:update) do |opts|
13
+ case update_sql(opts)
14
+ when /UPDATE people SET (name|#{lv}) = ('Jim'|'Bob'|\d+), (?:name|#{lv}) = ('Jim'|'Bob'|\d+) WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
15
+ name, nlv = $1 == 'name' ? [$2, $3] : [$3, $2]
16
+ m = h[$4.to_i]
17
+ if m && m[:lock_version] == $5.to_i
18
+ m.merge!(:name=>name.gsub("'", ''), :lock_version=>nlv.to_i)
19
+ 1
20
+ else
21
+ 0
22
+ end
23
+ else
24
+ puts update_sql(opts)
25
+ end
26
+ end
27
+ @c.dataset.instance_eval do
28
+ def fetch_rows(sql)
29
+ m = h[1].dup
30
+ v = m.delete(:lock_version)
31
+ m[lv.to_sym] = v
32
+ yield(m)
33
+ end
34
+ end
35
+ @c.dataset.meta_def(:delete) do
36
+ case delete_sql
37
+ when /DELETE FROM people WHERE \(\(id = (\d+)\) AND \(#{lv} = (\d+)\)\)/
38
+ m = h[$1.to_i]
39
+ if m && m[lv.to_sym] == $2.to_i
40
+ h.delete[$1.to_i]
41
+ 1
42
+ else
43
+ 0
44
+ end
45
+ else
46
+ puts delete_sql
47
+ end
48
+ end
49
+ @c.columns :id, :name, :lock_version
50
+ @c.plugin :optimistic_locking
51
+ end
52
+
53
+ specify "should raise an error when updating a stale record" do
54
+ p1 = @c[1]
55
+ p2 = @c[1]
56
+ p1.update(:name=>'Jim')
57
+ proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
58
+ end
59
+
60
+ specify "should raise an error when destroying a stale record" do
61
+ p1 = @c[1]
62
+ p2 = @c[1]
63
+ p1.update(:name=>'Jim')
64
+ proc{p2.destroy}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
65
+ end
66
+
67
+ specify "should not raise an error when updating the same record twice" do
68
+ p1 = @c[1]
69
+ p1.update(:name=>'Jim')
70
+ proc{p1.update(:name=>'Bob')}.should_not raise_error
71
+ end
72
+
73
+ specify "should allow changing the lock column via model.lock_column=" do
74
+ @lv.replace('lv')
75
+ @c.columns :id, :name, :lv
76
+ @c.lock_column = :lv
77
+ p1 = @c[1]
78
+ p2 = @c[1]
79
+ p1.update(:name=>'Jim')
80
+ proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
81
+ end
82
+
83
+ specify "should allow changing the lock column via plugin option" do
84
+ @lv.replace('lv')
85
+ @c.columns :id, :name, :lv
86
+ @c.plugin :optimistic_locking, :lock_column=>:lv
87
+ p1 = @c[1]
88
+ p2 = @c[1]
89
+ p1.update(:name=>'Jim')
90
+ proc{p2.destroy}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
91
+ end
92
+
93
+ specify "should work when subclassing" do
94
+ c = Class.new(@c)
95
+ p1 = c[1]
96
+ p2 = c[1]
97
+ p1.update(:name=>'Jim')
98
+ proc{p2.update(:name=>'Bob')}.should raise_error(Sequel::Plugins::OptimisticLocking::Error)
99
+ end
100
+ end
@@ -0,0 +1,99 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ context "A paginated dataset" do
4
+ before do
5
+ @d = Sequel::Dataset.new(nil)
6
+ @d.meta_def(:count) {153}
7
+
8
+ @paginated = @d.paginate(1, 20)
9
+ end
10
+
11
+ specify "should raise an error if the dataset already has a limit" do
12
+ proc{@d.limit(10).paginate(1,10)}.should raise_error(Sequel::Error)
13
+ proc{@paginated.paginate(2,20)}.should raise_error(Sequel::Error)
14
+ end
15
+
16
+ specify "should set the limit and offset options correctly" do
17
+ @paginated.opts[:limit].should == 20
18
+ @paginated.opts[:offset].should == 0
19
+ end
20
+
21
+ specify "should set the page count correctly" do
22
+ @paginated.page_count.should == 8
23
+ @d.paginate(1, 50).page_count.should == 4
24
+ end
25
+
26
+ specify "should set the current page number correctly" do
27
+ @paginated.current_page.should == 1
28
+ @d.paginate(3, 50).current_page.should == 3
29
+ end
30
+
31
+ specify "should return the next page number or nil if we're on the last" do
32
+ @paginated.next_page.should == 2
33
+ @d.paginate(4, 50).next_page.should be_nil
34
+ end
35
+
36
+ specify "should return the previous page number or nil if we're on the last" do
37
+ @paginated.prev_page.should be_nil
38
+ @d.paginate(4, 50).prev_page.should == 3
39
+ end
40
+
41
+ specify "should return the page range" do
42
+ @paginated.page_range.should == (1..8)
43
+ @d.paginate(4, 50).page_range.should == (1..4)
44
+ end
45
+
46
+ specify "should return the record range for the current page" do
47
+ @paginated.current_page_record_range.should == (1..20)
48
+ @d.paginate(4, 50).current_page_record_range.should == (151..153)
49
+ @d.paginate(5, 50).current_page_record_range.should == (0..0)
50
+ end
51
+
52
+ specify "should return the record count for the current page" do
53
+ @paginated.current_page_record_count.should == 20
54
+ @d.paginate(3, 50).current_page_record_count.should == 50
55
+ @d.paginate(4, 50).current_page_record_count.should == 3
56
+ @d.paginate(5, 50).current_page_record_count.should == 0
57
+ end
58
+
59
+ specify "should know if current page is last page" do
60
+ @paginated.last_page?.should be_false
61
+ @d.paginate(2, 20).last_page?.should be_false
62
+ @d.paginate(5, 30).last_page?.should be_false
63
+ @d.paginate(6, 30).last_page?.should be_true
64
+ end
65
+
66
+ specify "should know if current page is first page" do
67
+ @paginated.first_page?.should be_true
68
+ @d.paginate(1, 20).first_page?.should be_true
69
+ @d.paginate(2, 20).first_page?.should be_false
70
+ end
71
+
72
+ specify "should work with fixed sql" do
73
+ ds = @d.clone(:sql => 'select * from blah')
74
+ ds.meta_def(:count) {150}
75
+ ds.paginate(2, 50).sql.should == 'SELECT * FROM (select * from blah) AS t1 LIMIT 50 OFFSET 50'
76
+ end
77
+ end
78
+
79
+ context "Dataset#each_page" do
80
+ before do
81
+ @d = Sequel::Dataset.new(nil).from(:items)
82
+ @d.meta_def(:count) {153}
83
+ end
84
+
85
+ specify "should raise an error if the dataset already has a limit" do
86
+ proc{@d.limit(10).each_page(10){}}.should raise_error(Sequel::Error)
87
+ end
88
+
89
+ specify "should iterate over each page in the resultset as a paginated dataset" do
90
+ a = []
91
+ @d.each_page(50) {|p| a << p}
92
+ a.map {|p| p.sql}.should == [
93
+ 'SELECT * FROM items LIMIT 50 OFFSET 0',
94
+ 'SELECT * FROM items LIMIT 50 OFFSET 50',
95
+ 'SELECT * FROM items LIMIT 50 OFFSET 100',
96
+ 'SELECT * FROM items LIMIT 50 OFFSET 150',
97
+ ]
98
+ end
99
+ end
@@ -0,0 +1,91 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ require 'stringio'
4
+
5
+ context "Dataset#print" do
6
+ before do
7
+ @output = StringIO.new
8
+ @orig_stdout = $stdout
9
+ $stdout = @output
10
+ @dataset = Sequel::Dataset.new(nil).from(:items)
11
+ def @dataset.fetch_rows(sql)
12
+ yield({:a=>1, :b=>2})
13
+ yield({:a=>3, :b=>4})
14
+ yield({:a=>5, :b=>6})
15
+ end
16
+ end
17
+
18
+ after do
19
+ $stdout = @orig_stdout
20
+ end
21
+
22
+ specify "should print out a table with the values" do
23
+ @dataset.print(:a, :b)
24
+ @output.rewind
25
+ @output.read.should == \
26
+ "+-+-+\n|a|b|\n+-+-+\n|1|2|\n|3|4|\n|5|6|\n+-+-+\n"
27
+ end
28
+
29
+ specify "should default to the dataset's columns" do
30
+ @dataset.meta_def(:columns) {[:a, :b]}
31
+ @dataset.print
32
+ @output.rewind
33
+ @output.read.should == \
34
+ "+-+-+\n|a|b|\n+-+-+\n|1|2|\n|3|4|\n|5|6|\n+-+-+\n"
35
+ end
36
+ end
37
+
38
+ context "PrettyTable" do
39
+ before do
40
+ @data1 = [
41
+ {:x => 3, :y => 4}
42
+ ]
43
+
44
+ @data2 = [
45
+ {:a => 23, :b => 45},
46
+ {:a => 45, :b => 2377}
47
+ ]
48
+
49
+ @data3 = [
50
+ {:aaa => 1},
51
+ {:bb => 2},
52
+ {:c => 3}
53
+ ]
54
+
55
+ @output = StringIO.new
56
+ @orig_stdout = $stdout
57
+ $stdout = @output
58
+ end
59
+
60
+ after do
61
+ $stdout = @orig_stdout
62
+ end
63
+
64
+ specify "should infer the columns if not given" do
65
+ Sequel::PrettyTable.print(@data1)
66
+ @output.rewind
67
+ @output.read.should =~ \
68
+ /\n(\|x\|y\|)|(\|y\|x\|)\n/
69
+ end
70
+
71
+ specify "should calculate the maximum width of each column correctly" do
72
+ Sequel::PrettyTable.print(@data2, [:a, :b])
73
+ @output.rewind
74
+ @output.read.should == \
75
+ "+--+----+\n|a |b |\n+--+----+\n|23| 45|\n|45|2377|\n+--+----+\n"
76
+ end
77
+
78
+ specify "should also take header width into account" do
79
+ Sequel::PrettyTable.print(@data3, [:aaa, :bb, :c])
80
+ @output.rewind
81
+ @output.read.should == \
82
+ "+---+--+-+\n|aaa|bb|c|\n+---+--+-+\n| 1| | |\n| | 2| |\n| | |3|\n+---+--+-+\n"
83
+ end
84
+
85
+ specify "should print only the specified columns" do
86
+ Sequel::PrettyTable.print(@data2, [:a])
87
+ @output.rewind
88
+ @output.read.should == \
89
+ "+--+\n|a |\n+--+\n|23|\n|45|\n+--+\n"
90
+ end
91
+ end
@@ -0,0 +1,85 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ context "Database#dataset" do
4
+ before do
5
+ @db = Sequel::Database.new
6
+ end
7
+
8
+ specify "should delegate to Dataset#query if block is provided" do
9
+ @d = @db.query {select :x; from :y}
10
+ @d.should be_a_kind_of(Sequel::Dataset)
11
+ @d.sql.should == "SELECT x FROM y"
12
+ end
13
+ end
14
+
15
+ context "Dataset#query" do
16
+ before do
17
+ @d = Sequel::Dataset.new(nil)
18
+ end
19
+
20
+ specify "should support #from" do
21
+ q = @d.query {from :xxx}
22
+ q.class.should == @d.class
23
+ q.sql.should == "SELECT * FROM xxx"
24
+ end
25
+
26
+ specify "should support #select" do
27
+ q = @d.query do
28
+ select :a, :b___mongo
29
+ from :yyy
30
+ end
31
+ q.class.should == @d.class
32
+ q.sql.should == "SELECT a, b AS mongo FROM yyy"
33
+ end
34
+
35
+ specify "should support #where" do
36
+ q = @d.query do
37
+ from :zzz
38
+ where(:x + 2 > :y + 3)
39
+ end
40
+ q.class.should == @d.class
41
+ q.sql.should == "SELECT * FROM zzz WHERE ((x + 2) > (y + 3))"
42
+
43
+ q = @d.from(:zzz).query do
44
+ where((:x.sql_number > 1) & (:y.sql_number > 2))
45
+ end
46
+ q.class.should == @d.class
47
+ q.sql.should == "SELECT * FROM zzz WHERE ((x > 1) AND (y > 2))"
48
+
49
+ q = @d.from(:zzz).query do
50
+ where :x => 33
51
+ end
52
+ q.class.should == @d.class
53
+ q.sql.should == "SELECT * FROM zzz WHERE (x = 33)"
54
+ end
55
+
56
+ specify "should support #group_by and #having" do
57
+ q = @d.query do
58
+ from :abc
59
+ group_by :id
60
+ having(:x.sql_number >= 2)
61
+ end
62
+ q.class.should == @d.class
63
+ q.sql.should == "SELECT * FROM abc GROUP BY id HAVING (x >= 2)"
64
+ end
65
+
66
+ specify "should support #order, #order_by" do
67
+ q = @d.query do
68
+ from :xyz
69
+ order_by :stamp
70
+ end
71
+ q.class.should == @d.class
72
+ q.sql.should == "SELECT * FROM xyz ORDER BY stamp"
73
+ end
74
+
75
+ specify "should raise on non-chainable method calls" do
76
+ proc {@d.query {first_source}}.should raise_error(Sequel::Error)
77
+ end
78
+
79
+ specify "should raise on each, insert, update, delete" do
80
+ proc {@d.query {each}}.should raise_error(Sequel::Error)
81
+ proc {@d.query {insert(:x => 1)}}.should raise_error(Sequel::Error)
82
+ proc {@d.query {update(:x => 1)}}.should raise_error(Sequel::Error)
83
+ proc {@d.query {delete}}.should raise_error(Sequel::Error)
84
+ end
85
+ end
@@ -0,0 +1,205 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe Sequel::Model, "rcte_tree" do
4
+ before do
5
+ @c = Class.new(Sequel::Model(MODEL_DB[:nodes]))
6
+ @c.class_eval do
7
+ def self.name; 'Node'; end
8
+ columns :id, :name, :parent_id, :i, :pi
9
+ end
10
+ @ds = @c.dataset
11
+ class << @ds
12
+ attr_accessor :row_sets
13
+ def fetch_rows(sql)
14
+ @db << sql
15
+ row_sets.shift.each{|row| yield row}
16
+ end
17
+ end
18
+ @o = @c.load(:id=>2, :parent_id=>1, :name=>'AA', :i=>3, :pi=>4)
19
+ MODEL_DB.reset
20
+ end
21
+
22
+ it "should define the correct associations" do
23
+ @c.plugin :rcte_tree
24
+ @c.associations.sort_by{|x| x.to_s}.should == [:ancestors, :children, :descendants, :parent]
25
+ end
26
+
27
+ it "should define the correct associations when giving options" do
28
+ @c.plugin :rcte_tree, :ancestors=>{:name=>:as}, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}, :parent=>{:name=>:p}
29
+ @c.associations.sort_by{|x| x.to_s}.should == [:as, :cs, :ds, :p]
30
+ end
31
+
32
+ it "should use the correct SQL for lazy associations" do
33
+ @c.plugin :rcte_tree
34
+ @o.parent_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1'
35
+ @o.children_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.parent_id = 2)'
36
+ @o.ancestors_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE (id = 1) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.parent_id = nodes.id)) SELECT * FROM t'
37
+ @o.descendants_dataset.sql.should == 'WITH t AS (SELECT * FROM nodes WHERE (parent_id = 2) UNION ALL SELECT nodes.* FROM nodes INNER JOIN t ON (t.id = nodes.parent_id)) SELECT * FROM t'
38
+ end
39
+
40
+ it "should use the correct SQL for lazy associations when giving options" do
41
+ @c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :cte_name=>:cte, :order=>:name, :ancestors=>{:name=>:as}, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}, :parent=>{:name=>:p}
42
+ @o.p_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.i = 4) ORDER BY name LIMIT 1'
43
+ @o.cs_dataset.sql.should == 'SELECT * FROM nodes WHERE (nodes.pi = 3) ORDER BY name'
44
+ @o.as_dataset.sql.should == 'WITH cte AS (SELECT * FROM nodes WHERE (i = 4) UNION ALL SELECT nodes.* FROM nodes INNER JOIN cte ON (cte.pi = nodes.i)) SELECT * FROM cte ORDER BY name'
45
+ @o.ds_dataset.sql.should == 'WITH cte AS (SELECT * FROM nodes WHERE (pi = 3) UNION ALL SELECT nodes.* FROM nodes INNER JOIN cte ON (cte.i = nodes.pi)) SELECT * FROM cte ORDER BY name'
46
+ end
47
+
48
+ it "should add all parent associations when lazily loading ancestors" do
49
+ @c.plugin :rcte_tree
50
+ @ds.row_sets = [[{:id=>1, :name=>'A', :parent_id=>3}, {:id=>4, :name=>'B', :parent_id=>nil}, {:id=>3, :name=>'?', :parent_id=>4}]]
51
+ @o.ancestors.should == [@c.load(:id=>1, :name=>'A', :parent_id=>3), @c.load(:id=>4, :name=>'B', :parent_id=>nil), @c.load(:id=>3, :name=>'?', :parent_id=>4)]
52
+ @o.associations[:parent].should == @c.load(:id=>1, :name=>'A', :parent_id=>3)
53
+ @o.associations[:parent].associations[:parent].should == @c.load(:id=>3, :name=>'?', :parent_id=>4)
54
+ @o.associations[:parent].associations[:parent].associations[:parent].should == @c.load(:id=>4, :name=>'B', :parent_id=>nil)
55
+ @o.associations[:parent].associations[:parent].associations[:parent].associations.fetch(:parent, 1).should == nil
56
+ end
57
+
58
+ it "should add all parent associations when lazily loading ancestors and giving options" do
59
+ @c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :ancestors=>{:name=>:as}, :parent=>{:name=>:p}
60
+ @ds.row_sets = [[{:i=>4, :name=>'A', :pi=>5}, {:i=>6, :name=>'B', :pi=>nil}, {:i=>5, :name=>'?', :pi=>6}]]
61
+ @o.as.should == [@c.load(:i=>4, :name=>'A', :pi=>5), @c.load(:i=>6, :name=>'B', :pi=>nil), @c.load(:i=>5, :name=>'?', :pi=>6)]
62
+ @o.associations[:p].should == @c.load(:i=>4, :name=>'A', :pi=>5)
63
+ @o.associations[:p].associations[:p].should == @c.load(:i=>5, :name=>'?', :pi=>6)
64
+ @o.associations[:p].associations[:p].associations[:p].should == @c.load(:i=>6, :name=>'B', :pi=>nil)
65
+ @o.associations[:p].associations[:p].associations[:p].associations.fetch(:p, 1).should == nil
66
+ end
67
+
68
+ it "should add all children associations when lazily loading descendants" do
69
+ @c.plugin :rcte_tree
70
+ @ds.row_sets = [[{:id=>3, :name=>'??', :parent_id=>1}, {:id=>1, :name=>'A', :parent_id=>2}, {:id=>4, :name=>'B', :parent_id=>2}, {:id=>5, :name=>'?', :parent_id=>3}]]
71
+ @o.descendants.should == [@c.load(:id=>3, :name=>'??', :parent_id=>1), @c.load(:id=>1, :name=>'A', :parent_id=>2), @c.load(:id=>4, :name=>'B', :parent_id=>2), @c.load(:id=>5, :name=>'?', :parent_id=>3)]
72
+ @o.associations[:children].should == [@c.load(:id=>1, :name=>'A', :parent_id=>2), @c.load(:id=>4, :name=>'B', :parent_id=>2)]
73
+ @o.associations[:children].map{|c1| c1.associations[:children]}.should == [[@c.load(:id=>3, :name=>'??', :parent_id=>1)], []]
74
+ @o.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children]}}.should == [[[@c.load(:id=>5, :name=>'?', :parent_id=>3)]], []]
75
+ @o.associations[:children].map{|c1| c1.associations[:children].map{|c2| c2.associations[:children].map{|c3| c3.associations[:children]}}}.should == [[[[]]], []]
76
+ end
77
+
78
+ it "should add all children associations when lazily loading descendants and giving options" do
79
+ @c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}
80
+ @ds.row_sets = [[{:i=>7, :name=>'??', :pi=>5}, {:i=>5, :name=>'A', :pi=>3}, {:i=>6, :name=>'B', :pi=>3}, {:i=>8, :name=>'?', :pi=>7}]]
81
+ @o.ds.should == [@c.load(:i=>7, :name=>'??', :pi=>5), @c.load(:i=>5, :name=>'A', :pi=>3), @c.load(:i=>6, :name=>'B', :pi=>3), @c.load(:i=>8, :name=>'?', :pi=>7)]
82
+ @o.associations[:cs].should == [@c.load(:i=>5, :name=>'A', :pi=>3), @c.load(:i=>6, :name=>'B', :pi=>3)]
83
+ @o.associations[:cs].map{|c1| c1.associations[:cs]}.should == [[@c.load(:i=>7, :name=>'??', :pi=>5)], []]
84
+ @o.associations[:cs].map{|c1| c1.associations[:cs].map{|c2| c2.associations[:cs]}}.should == [[[@c.load(:i=>8, :name=>'?', :pi=>7)]], []]
85
+ @o.associations[:cs].map{|c1| c1.associations[:cs].map{|c2| c2.associations[:cs].map{|c3| c3.associations[:cs]}}}.should == [[[[]]], []]
86
+ end
87
+
88
+ it "should eagerly load ancestors" do
89
+ @c.plugin :rcte_tree
90
+ @ds.row_sets = [[{:id=>2, :parent_id=>1, :name=>'AA'}, {:id=>6, :parent_id=>2, :name=>'C'}, {:id=>7, :parent_id=>1, :name=>'D'}, {:id=>9, :parent_id=>nil, :name=>'E'}],
91
+ [{:id=>2, :name=>'AA', :parent_id=>1, :x_root_x=>2},
92
+ {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>1}, {:id=>1, :name=>'00', :parent_id=>8, :x_root_x=>2},
93
+ {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>2}, {:id=>8, :name=>'?', :parent_id=>nil, :x_root_x=>1}]]
94
+ os = @ds.eager(:ancestors).all
95
+ MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
96
+ MODEL_DB.new_sqls.last.should =~ /WITH t AS \(SELECT id AS x_root_x, nodes\.\* FROM nodes WHERE \(id IN \([12], [12]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.parent_id = nodes\.id\)\) SELECT \* FROM t/
97
+ os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D'), @c.load(:id=>9, :parent_id=>nil, :name=>'E')]
98
+ os.map{|o| o.ancestors}.should == [[@c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil)],
99
+ [@c.load(:id=>2, :name=>'AA', :parent_id=>1), @c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil)],
100
+ [@c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil)],
101
+ []]
102
+ os.map{|o| o.parent}.should == [@c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>2, :name=>'AA', :parent_id=>1), @c.load(:id=>1, :name=>'00', :parent_id=>8), nil]
103
+ os.map{|o| o.parent.parent if o.parent}.should == [@c.load(:id=>8, :name=>'?', :parent_id=>nil), @c.load(:id=>1, :name=>'00', :parent_id=>8), @c.load(:id=>8, :name=>'?', :parent_id=>nil), nil]
104
+ os.map{|o| o.parent.parent.parent if o.parent and o.parent.parent}.should == [nil, @c.load(:id=>8, :name=>'?', :parent_id=>nil), nil, nil]
105
+ os.map{|o| o.parent.parent.parent.parent if o.parent and o.parent.parent and o.parent.parent.parent}.should == [nil, nil, nil, nil]
106
+ MODEL_DB.new_sqls.should == []
107
+ end
108
+
109
+ it "should eagerly load ancestors when giving options" do
110
+ @c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :key_alias=>:kal, :cte_name=>:cte, :ancestors=>{:name=>:as}, :parent=>{:name=>:p}
111
+ @ds.row_sets = [[{:i=>2, :pi=>1, :name=>'AA'}, {:i=>6, :pi=>2, :name=>'C'}, {:i=>7, :pi=>1, :name=>'D'}, {:i=>9, :pi=>nil, :name=>'E'}],
112
+ [{:i=>2, :name=>'AA', :pi=>1, :kal=>2},
113
+ {:i=>1, :name=>'00', :pi=>8, :kal=>1}, {:i=>1, :name=>'00', :pi=>8, :kal=>2},
114
+ {:i=>8, :name=>'?', :pi=>nil, :kal=>2}, {:i=>8, :name=>'?', :pi=>nil, :kal=>1}]]
115
+ os = @ds.eager(:as).all
116
+ MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
117
+ MODEL_DB.new_sqls.last.should =~ /WITH cte AS \(SELECT i AS kal, nodes\.\* FROM nodes WHERE \(i IN \([12], [12]\)\) UNION ALL SELECT cte\.kal, nodes\.\* FROM nodes INNER JOIN cte ON \(cte\.pi = nodes\.i\)\) SELECT \* FROM cte/
118
+ os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D'), @c.load(:i=>9, :pi=>nil, :name=>'E')]
119
+ os.map{|o| o.as}.should == [[@c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil)],
120
+ [@c.load(:i=>2, :name=>'AA', :pi=>1), @c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil)],
121
+ [@c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil)],
122
+ []]
123
+ os.map{|o| o.p}.should == [@c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>2, :name=>'AA', :pi=>1), @c.load(:i=>1, :name=>'00', :pi=>8), nil]
124
+ os.map{|o| o.p.p if o.p}.should == [@c.load(:i=>8, :name=>'?', :pi=>nil), @c.load(:i=>1, :name=>'00', :pi=>8), @c.load(:i=>8, :name=>'?', :pi=>nil), nil]
125
+ os.map{|o| o.p.p.p if o.p and o.p.p}.should == [nil, @c.load(:i=>8, :name=>'?', :pi=>nil), nil, nil]
126
+ os.map{|o| o.p.p.p.p if o.p and o.p.p and o.p.p.p}.should == [nil, nil, nil, nil]
127
+ MODEL_DB.new_sqls.should == []
128
+ end
129
+
130
+ it "should eagerly load descendants" do
131
+ @c.plugin :rcte_tree
132
+ @ds.row_sets = [[{:id=>2, :parent_id=>1, :name=>'AA'}, {:id=>6, :parent_id=>2, :name=>'C'}, {:id=>7, :parent_id=>1, :name=>'D'}],
133
+ [{:id=>6, :parent_id=>2, :name=>'C', :x_root_x=>2}, {:id=>9, :parent_id=>2, :name=>'E', :x_root_x=>2},
134
+ {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2},
135
+ {:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7}]]
136
+ os = @ds.eager(:descendants).all
137
+ MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
138
+ MODEL_DB.new_sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\* FROM nodes WHERE \(parent_id IN \([267], [267], [267]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\* FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\)\) SELECT \* FROM t/
139
+ os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D')]
140
+ os.map{|o| o.descendants}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E'), @c.load(:id=>3, :name=>'00', :parent_id=>6)],
141
+ [@c.load(:id=>3, :name=>'00', :parent_id=>6)],
142
+ [@c.load(:id=>4, :name=>'?', :parent_id=>7), @c.load(:id=>5, :name=>'?', :parent_id=>4)]]
143
+ os.map{|o| o.children}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E')], [@c.load(:id=>3, :name=>'00', :parent_id=>6)], [@c.load(:id=>4, :name=>'?', :parent_id=>7)]]
144
+ os.map{|o1| o1.children.map{|o2| o2.children}}.should == [[[@c.load(:id=>3, :name=>'00', :parent_id=>6)], []], [[]], [[@c.load(:id=>5, :name=>'?', :parent_id=>4)]]]
145
+ os.map{|o1| o1.children.map{|o2| o2.children.map{|o3| o3.children}}}.should == [[[[]], []], [[]], [[[]]]]
146
+ MODEL_DB.new_sqls.should == []
147
+ end
148
+
149
+ it "should eagerly load descendants when giving options" do
150
+ @c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :key_alias=>:kal, :cte_name=>:cte, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}
151
+ @ds.row_sets = [[{:i=>2, :pi=>1, :name=>'AA'}, {:i=>6, :pi=>2, :name=>'C'}, {:i=>7, :pi=>1, :name=>'D'}],
152
+ [{:i=>6, :pi=>2, :name=>'C', :kal=>2}, {:i=>9, :pi=>2, :name=>'E', :kal=>2},
153
+ {:i=>3, :name=>'00', :pi=>6, :kal=>6}, {:i=>3, :name=>'00', :pi=>6, :kal=>2},
154
+ {:i=>4, :name=>'?', :pi=>7, :kal=>7}, {:i=>5, :name=>'?', :pi=>4, :kal=>7}]]
155
+ os = @ds.eager(:ds).all
156
+ MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
157
+ MODEL_DB.new_sqls.last.should =~ /WITH cte AS \(SELECT pi AS kal, nodes\.\* FROM nodes WHERE \(pi IN \([267], [267], [267]\)\) UNION ALL SELECT cte\.kal, nodes\.\* FROM nodes INNER JOIN cte ON \(cte\.i = nodes\.pi\)\) SELECT \* FROM cte/
158
+ os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D')]
159
+ os.map{|o| o.ds}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E'), @c.load(:i=>3, :name=>'00', :pi=>6)],
160
+ [@c.load(:i=>3, :name=>'00', :pi=>6)],
161
+ [@c.load(:i=>4, :name=>'?', :pi=>7), @c.load(:i=>5, :name=>'?', :pi=>4)]]
162
+ os.map{|o| o.cs}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E')], [@c.load(:i=>3, :name=>'00', :pi=>6)], [@c.load(:i=>4, :name=>'?', :pi=>7)]]
163
+ os.map{|o1| o1.cs.map{|o2| o2.cs}}.should == [[[@c.load(:i=>3, :name=>'00', :pi=>6)], []], [[]], [[@c.load(:i=>5, :name=>'?', :pi=>4)]]]
164
+ os.map{|o1| o1.cs.map{|o2| o2.cs.map{|o3| o3.cs}}}.should == [[[[]], []], [[]], [[[]]]]
165
+ MODEL_DB.new_sqls.should == []
166
+ end
167
+
168
+ it "should eagerly load descendants to a given level" do
169
+ @c.plugin :rcte_tree
170
+ @ds.row_sets = [[{:id=>2, :parent_id=>1, :name=>'AA'}, {:id=>6, :parent_id=>2, :name=>'C'}, {:id=>7, :parent_id=>1, :name=>'D'}],
171
+ [{:id=>6, :parent_id=>2, :name=>'C', :x_root_x=>2, :x_level_x=>0}, {:id=>9, :parent_id=>2, :name=>'E', :x_root_x=>2, :x_level_x=>0},
172
+ {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>6, :x_level_x=>0}, {:id=>3, :name=>'00', :parent_id=>6, :x_root_x=>2, :x_level_x=>1},
173
+ {:id=>4, :name=>'?', :parent_id=>7, :x_root_x=>7, :x_level_x=>0}, {:id=>5, :name=>'?', :parent_id=>4, :x_root_x=>7, :x_level_x=>1}]]
174
+ os = @ds.eager(:descendants=>2).all
175
+ MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
176
+ MODEL_DB.new_sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x, nodes\.\*, 0 AS x_level_x FROM nodes WHERE \(parent_id IN \([267], [267], [267]\)\) UNION ALL SELECT t\.x_root_x, nodes\.\*, \(t\.x_level_x \+ 1\) AS x_level_x FROM nodes INNER JOIN t ON \(t\.id = nodes\.parent_id\) WHERE \(t\.x_level_x < 1\)\) SELECT \* FROM t/
177
+ os.should == [@c.load(:id=>2, :parent_id=>1, :name=>'AA'), @c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>7, :parent_id=>1, :name=>'D')]
178
+ os.map{|o| o.descendants}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E'), @c.load(:id=>3, :name=>'00', :parent_id=>6)],
179
+ [@c.load(:id=>3, :name=>'00', :parent_id=>6)],
180
+ [@c.load(:id=>4, :name=>'?', :parent_id=>7), @c.load(:id=>5, :name=>'?', :parent_id=>4)]]
181
+ os.map{|o| o.associations[:children]}.should == [[@c.load(:id=>6, :parent_id=>2, :name=>'C'), @c.load(:id=>9, :parent_id=>2, :name=>'E')], [@c.load(:id=>3, :name=>'00', :parent_id=>6)], [@c.load(:id=>4, :name=>'?', :parent_id=>7)]]
182
+ os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children]}}.should == [[[@c.load(:id=>3, :name=>'00', :parent_id=>6)], []], [[]], [[@c.load(:id=>5, :name=>'?', :parent_id=>4)]]]
183
+ os.map{|o1| o1.associations[:children].map{|o2| o2.associations[:children].map{|o3| o3.associations[:children]}}}.should == [[[[]], []], [[]], [[nil]]]
184
+ MODEL_DB.new_sqls.should == []
185
+ end
186
+
187
+ it "should eagerly load descendants to a given level when giving options" do
188
+ @c.plugin :rcte_tree, :primary_key=>:i, :key=>:pi, :key_alias=>:kal, :level_alias=>:lal, :cte_name=>:cte, :children=>{:name=>:cs}, :descendants=>{:name=>:ds}
189
+ @ds.row_sets = [[{:i=>2, :pi=>1, :name=>'AA'}, {:i=>6, :pi=>2, :name=>'C'}, {:i=>7, :pi=>1, :name=>'D'}],
190
+ [{:i=>6, :pi=>2, :name=>'C', :kal=>2, :lal=>0}, {:i=>9, :pi=>2, :name=>'E', :kal=>2, :lal=>0},
191
+ {:i=>3, :name=>'00', :pi=>6, :kal=>6, :lal=>0}, {:i=>3, :name=>'00', :pi=>6, :kal=>2, :lal=>1},
192
+ {:i=>4, :name=>'?', :pi=>7, :kal=>7, :lal=>0}, {:i=>5, :name=>'?', :pi=>4, :kal=>7, :lal=>1}]]
193
+ os = @ds.eager(:ds=>2).all
194
+ MODEL_DB.sqls.first.should == "SELECT * FROM nodes"
195
+ MODEL_DB.new_sqls.last.should =~ /WITH cte AS \(SELECT pi AS kal, nodes\.\*, 0 AS lal FROM nodes WHERE \(pi IN \([267], [267], [267]\)\) UNION ALL SELECT cte\.kal, nodes\.\*, \(cte\.lal \+ 1\) AS lal FROM nodes INNER JOIN cte ON \(cte\.i = nodes\.pi\) WHERE \(cte\.lal < 1\)\) SELECT \* FROM cte/
196
+ os.should == [@c.load(:i=>2, :pi=>1, :name=>'AA'), @c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>7, :pi=>1, :name=>'D')]
197
+ os.map{|o| o.ds}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E'), @c.load(:i=>3, :name=>'00', :pi=>6)],
198
+ [@c.load(:i=>3, :name=>'00', :pi=>6)],
199
+ [@c.load(:i=>4, :name=>'?', :pi=>7), @c.load(:i=>5, :name=>'?', :pi=>4)]]
200
+ os.map{|o| o.associations[:cs]}.should == [[@c.load(:i=>6, :pi=>2, :name=>'C'), @c.load(:i=>9, :pi=>2, :name=>'E')], [@c.load(:i=>3, :name=>'00', :pi=>6)], [@c.load(:i=>4, :name=>'?', :pi=>7)]]
201
+ os.map{|o1| o1.associations[:cs].map{|o2| o2.associations[:cs]}}.should == [[[@c.load(:i=>3, :name=>'00', :pi=>6)], []], [[]], [[@c.load(:i=>5, :name=>'?', :pi=>4)]]]
202
+ os.map{|o1| o1.associations[:cs].map{|o2| o2.associations[:cs].map{|o3| o3.associations[:cs]}}}.should == [[[[]], []], [[]], [[nil]]]
203
+ MODEL_DB.new_sqls.should == []
204
+ end
205
+ end