viking-sequel 3.10.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.
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